Skip to content

Commit 1596aa4

Browse files
dcalhounclaude
andauthored
Enable Google Photos in the device media picker (#23102)
* feat(media): disambiguate in-grid device picker by media type When the custom media grid's "Choose from device" action allows both visual media and other files (the editor's add-file flow), tapping it now shows a menu anchored to the action-bar item: "Photos and videos" opens the visual picker (which the OS surfaces as the Android Photo Picker on Android 13+), and "Other files" opens the document/audio chooser. Flows with a single known type (featured image, site icon, gravatar, editor photo/video) launch their picker directly, unchanged. This preserves the custom grid's edit-before-upload capability while enabling Google Photos browsing via the nested device picker. - MediaPickerFragment: carry allowedTypes on OpenSystemPicker; add an onSystemPickerTypeChosen passthrough. - MediaPickerViewModel: pass allowedTypes through; re-run the picker with a narrowed type set on menu selection; restrict the {AUDIO, DOCUMENT} context to audio + document MIME types. - MediaPickerActivity: show the disambiguation PopupMenu anchored to the browse action item when the selection is ambiguous. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(media): show Google Photos albums in the system photo picker For visual-media contexts, Android 13+ routes ACTION_GET_CONTENT to the system Photo Picker, which filters album and cloud contents by an exact match against EXTRA_MIME_TYPES. Passing our explicit list of accepted subtypes (image/jpeg, image/heic, ...) made Google Photos albums and "From this device" appear empty ("No photos yet"), because cloud items may not report a subtype in that list. Use a broad type (image/* and/or video/*) for the PHOTO, VIDEO, and PHOTO_OR_VIDEO contexts so the picker shows all visual media, matching how other apps behave. Audio and document flows use the document browser and keep the explicit accepted-types list. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(release-notes): note Google Photos browsing in the media picker Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(media): avoid double-tracking device-library open in disambiguation Picking a category from the "Photos and videos" / "Other files" disambiguation menu re-triggered the icon click, which fired the MEDIA_PICKER_OPEN_DEVICE_LIBRARY event a second time (the first firing happened when the menu was shown, before any picker opened). Split the navigation out of clickIcon so the category re-trigger navigates without tracking again. Also tighten the {AUDIO, DOCUMENT} chooser branch to an exact set match instead of a containsAll subset test, so only the disambiguation "Other files" selection routes there. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(media): move picker-type disambiguation decision into the ViewModel The Activity previously re-derived the visual-vs-other-files classification to decide whether to show the disambiguation menu, duplicating the allowedTypes taxonomy the ViewModel already owns. The ViewModel now makes that decision and emits a dedicated ShowSystemPickerTypeMenu action; the Activity just renders the menu. This also corrects the "device library opened" analytics timing: the ambiguous tap now shows the menu without tracking, and the open is tracked when the user picks a category (the point at which a picker actually opens), so dismissing the menu no longer counts as an open. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(media): cover picker-type disambiguation and open-tracking timing Update the "all supported files" test to expect the new ShowSystemPickerTypeMenu action, and add coverage for choosing a category (photos/videos -> PHOTO_OR_VIDEO, other files -> MEDIA_FILE) and for the device-library open being tracked on category choice rather than when the disambiguation menu is shown. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(media): extract system picker type resolution into a collaborator Move the allowedTypes -> (ChooserContext, MIME types) mapping and the visual-vs-other-files ambiguity check out of MediaPickerViewModel into a new SystemPickerResolver. This keeps the ViewModel under detekt's LargeClass threshold (the disambiguation additions had pushed it over) and makes the picker-type resolution independently testable. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(media): let "Other files" browse all accepted types, not just audio/docs The disambiguation "Other files" option scoped the document browser to audio and documents only, which regressed the pre-disambiguation file picker: an image or video reachable only by browsing the filesystem (e.g. a freshly downloaded image in Downloads that the Photo Picker hasn't surfaced) could no longer be selected. Send the full accepted- types set so ACTION_OPEN_DOCUMENT shows images, videos, audio, and documents, matching trunk's file picker. Remove the now-unused audio+documents-only resolver branch. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * style(media): use `is` for ShowSystemPickerTypeMenu when-branch Match the surrounding branches (including the OpenCameraForPhotos object) which use `is` for their type checks, for consistency. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: Clarify EditorPhotoPicker no-op * refactor(media): make the resolver the single source of visual MIME types The broad image/* and video/* wildcards for the Photo Picker were decided in WPMediaUtils.getMimeTypesForChooser, which overrode and discarded the explicit subtype lists SystemPickerResolver had computed for the same visual contexts. That left dead data in the resolver and duplicated the ChooserContext -> MIME mapping across two files and two languages. Move the wildcards into the resolver (the sole producer of OpenSystemPicker) and drop the override so prepareChooserIntent uses the resolved MIME types directly. Behavior is unchanged; add assertions locking in image/* and image/*+video/* for the visual contexts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(media): show Google Photos albums in the editor's device picker The editor's "Browse" flow (EditorPhotoPicker -> WPMediaUtils.launchMediaLibrary -> prepareMediaLibraryIntent) still passed our explicit accepted-subtype list as EXTRA_MIME_TYPES, the same pattern that makes the Android 13+ system Photo Picker show Google Photos albums as empty ("No photos yet"). This route bypasses prepareChooserIntent, so the earlier broadening fix did not cover it. Use broad image/* and video/* wildcards so the picker shows all album/cloud media, matching the fix already applied to the media grid's system-picker route. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 7212d29 commit 1596aa4

9 files changed

Lines changed: 221 additions & 35 deletions

File tree

RELEASE-NOTES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
27.0
44
-----
5+
* [*] You can now browse Google Photos (albums, collections, and search) when adding photos or videos from your device.
56

67

78
26.9

WordPress/src/main/java/org/wordpress/android/ui/mediapicker/MediaPickerActivity.kt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import android.net.Uri
77
import android.os.Bundle
88
import android.text.TextUtils
99
import android.view.MenuItem
10+
import android.view.View
11+
import androidx.appcompat.widget.PopupMenu
1012
import androidx.fragment.app.FragmentTransaction
1113
import org.wordpress.android.BuildConfig
1214
import org.wordpress.android.R
@@ -28,6 +30,7 @@ import org.wordpress.android.ui.mediapicker.MediaPickerFragment.Companion.newIns
2830
import org.wordpress.android.ui.mediapicker.MediaPickerFragment.MediaPickerAction
2931
import org.wordpress.android.ui.mediapicker.MediaPickerFragment.MediaPickerAction.OpenCameraForPhotos
3032
import org.wordpress.android.ui.mediapicker.MediaPickerFragment.MediaPickerAction.OpenSystemPicker
33+
import org.wordpress.android.ui.mediapicker.MediaPickerFragment.MediaPickerAction.ShowSystemPickerTypeMenu
3134
import org.wordpress.android.ui.mediapicker.MediaPickerFragment.MediaPickerAction.SwitchMediaPicker
3235
import org.wordpress.android.ui.mediapicker.MediaPickerFragment.MediaPickerListener
3336
import org.wordpress.android.ui.mediapicker.MediaPickerSetup.DataSource
@@ -248,6 +251,28 @@ class MediaPickerActivity : BaseAppCompatActivity(), MediaPickerListener {
248251
WPMediaUtils.launchChooserWithContext(this, openSystemPicker, uiHelpers, MEDIA_LIBRARY)
249252
}
250253

254+
private fun showSystemPickerTypeMenu() {
255+
// Anchor to the "Choose from device" action-bar item so the menu appears attached to it;
256+
// fall back to the toolbar if the item is currently in the overflow and has no own view.
257+
val anchor = findViewById<View>(R.id.mnu_browse_item) ?: findViewById(R.id.toolbar_main)
258+
val popup = PopupMenu(this, anchor)
259+
popup.menu.add(R.string.photo_picker_choose_photo_or_video).setOnMenuItemClickListener {
260+
pickerFragment?.onSystemPickerTypeChosen(setOf(MediaType.IMAGE, MediaType.VIDEO))
261+
true
262+
}
263+
popup.menu.add(R.string.photo_picker_choose_other_files).setOnMenuItemClickListener {
264+
// "Other files" opens the document browser (ACTION_OPEN_DOCUMENT) with all accepted types,
265+
// matching the pre-disambiguation file picker. This keeps non-visual files reachable while
266+
// still allowing an image/video to be picked by browsing the filesystem (e.g. a freshly
267+
// downloaded image in Downloads that the Photo Picker may not surface yet).
268+
pickerFragment?.onSystemPickerTypeChosen(
269+
setOf(MediaType.IMAGE, MediaType.VIDEO, MediaType.AUDIO, MediaType.DOCUMENT)
270+
)
271+
true
272+
}
273+
popup.show()
274+
}
275+
251276
private fun Intent.putUris(
252277
mediaUris: List<Uri>
253278
) {
@@ -311,6 +336,9 @@ class MediaPickerActivity : BaseAppCompatActivity(), MediaPickerListener {
311336
is OpenSystemPicker -> {
312337
launchChooserWithContext(action, uiHelpers)
313338
}
339+
ShowSystemPickerTypeMenu -> {
340+
showSystemPickerTypeMenu()
341+
}
314342
is SwitchMediaPicker -> {
315343
startActivityForResult(buildIntent(this, action.mediaPickerSetup, site, localPostId), PHOTO_PICKER)
316344
}

WordPress/src/main/java/org/wordpress/android/ui/mediapicker/MediaPickerFragment.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ class MediaPickerFragment : Fragment(), MenuProvider {
114114
val allowMultipleSelection: Boolean
115115
) : MediaPickerAction()
116116

117+
// Shown when the flow allows both visual media and other files: the system Photo Picker only
118+
// surfaces visual media, so we let the user pick a category before opening a picker.
119+
object ShowSystemPickerTypeMenu : MediaPickerAction()
120+
117121
object OpenCameraForPhotos : MediaPickerAction()
118122
data class SwitchMediaPicker(val mediaPickerSetup: MediaPickerSetup) : MediaPickerAction()
119123
}
@@ -402,6 +406,10 @@ class MediaPickerFragment : Fragment(), MenuProvider {
402406
viewModel.urisSelectedFromSystemPicker(uris.map { UriWrapper(it) })
403407
}
404408

409+
fun onSystemPickerTypeChosen(allowedTypes: Set<MediaType>) {
410+
viewModel.onSystemPickerTypeChosen(allowedTypes)
411+
}
412+
405413
private fun initializeSearchView(actionMenuItem: MenuItem) {
406414
var isExpanding = false
407415
actionMenuItem.setOnActionExpandListener(object : OnActionExpandListener {

WordPress/src/main/java/org/wordpress/android/ui/mediapicker/MediaPickerViewModel.kt

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import org.wordpress.android.R
1313
import org.wordpress.android.fluxc.model.MediaModel
1414
import org.wordpress.android.fluxc.model.SiteModel
1515
import org.wordpress.android.fluxc.store.MediaStore
16-
import org.wordpress.android.fluxc.utils.MimeTypes
1716
import org.wordpress.android.modules.BG_THREAD
1817
import org.wordpress.android.modules.UI_THREAD
1918
import org.wordpress.android.ui.mediapicker.MediaItem.Identifier
@@ -22,10 +21,10 @@ import org.wordpress.android.ui.mediapicker.MediaNavigationEvent.Exit
2221
import org.wordpress.android.ui.mediapicker.MediaNavigationEvent.IconClickEvent
2322
import org.wordpress.android.ui.mediapicker.MediaNavigationEvent.PreviewMedia
2423
import org.wordpress.android.ui.mediapicker.MediaNavigationEvent.PreviewUrl
25-
import org.wordpress.android.ui.mediapicker.MediaPickerFragment.ChooserContext
2624
import org.wordpress.android.ui.mediapicker.MediaPickerFragment.MediaPickerAction
2725
import org.wordpress.android.ui.mediapicker.MediaPickerFragment.MediaPickerAction.OpenCameraForPhotos
2826
import org.wordpress.android.ui.mediapicker.MediaPickerFragment.MediaPickerAction.OpenSystemPicker
27+
import org.wordpress.android.ui.mediapicker.MediaPickerFragment.MediaPickerAction.ShowSystemPickerTypeMenu
2928
import org.wordpress.android.ui.mediapicker.MediaPickerFragment.MediaPickerAction.SwitchMediaPicker
3029
import org.wordpress.android.ui.mediapicker.MediaPickerFragment.MediaPickerIcon
3130
import org.wordpress.android.ui.mediapicker.MediaPickerFragment.MediaPickerIcon.CapturePhoto
@@ -78,7 +77,8 @@ class MediaPickerViewModel @Inject constructor(
7877
private val localeManagerWrapper: LocaleManagerWrapper,
7978
private val mediaUtilsWrapper: MediaUtilsWrapper,
8079
private val mediaStore: MediaStore,
81-
private val resourceProvider: ResourceProvider
80+
private val resourceProvider: ResourceProvider,
81+
private val systemPickerResolver: SystemPickerResolver
8282
) : ScopedViewModel(mainDispatcher) {
8383
private lateinit var mediaLoader: MediaLoader
8484
private lateinit var mediaInsertHandler: MediaInsertHandler
@@ -500,16 +500,27 @@ class MediaPickerViewModel @Inject constructor(
500500
fun clickOnLastTappedIcon() = clickIcon(lastTappedIcon!!)
501501

502502
private fun clickIcon(icon: MediaPickerIcon) {
503+
// When the device picker allows both visual media and other files, the actual library isn't
504+
// opened yet: we first show a type-disambiguation menu. Defer tracking the "device library
505+
// opened" event until the user picks a category (see onSystemPickerTypeChosen).
506+
if (icon is ChooseFromAndroidDevice &&
507+
systemPickerResolver.isAmbiguousMediaAndFileSelection(icon.allowedTypes)
508+
) {
509+
_onNavigate.postValue(Event(IconClickEvent(ShowSystemPickerTypeMenu)))
510+
return
511+
}
503512
mediaPickerTracker.trackIconClick(icon, mediaPickerSetup)
513+
navigateForIcon(icon)
514+
}
515+
516+
private fun navigateForIcon(icon: MediaPickerIcon) {
504517
if (icon is CapturePhoto) {
505518
if (!permissionsHandler.hasPermissionsToTakePhoto()) {
506519
_onCameraPermissionsRequested.value = Event(Unit)
507520
lastTappedIcon = icon
508521
return
509522
}
510523
}
511-
// Do we need tracking here?; review tracking need.
512-
513524
_onNavigate.postValue(Event(populateIconClickEvent(icon, mediaPickerSetup.canMultiselect)))
514525
}
515526

@@ -525,31 +536,8 @@ class MediaPickerViewModel @Inject constructor(
525536
private fun populateIconClickEvent(icon: MediaPickerIcon, canMultiselect: Boolean): IconClickEvent {
526537
val action: MediaPickerAction = when (icon) {
527538
is ChooseFromAndroidDevice -> {
528-
val allowedTypes = icon.allowedTypes
529-
val (context, types) = when {
530-
listOf(IMAGE).containsAll(allowedTypes) -> {
531-
Pair(ChooserContext.PHOTO, MimeTypes().getImageTypesOnly())
532-
}
533-
listOf(VIDEO).containsAll(allowedTypes) -> {
534-
Pair(ChooserContext.VIDEO, MimeTypes().getVideoTypesOnly())
535-
}
536-
listOf(IMAGE, VIDEO).containsAll(allowedTypes) -> {
537-
Pair(ChooserContext.PHOTO_OR_VIDEO, MimeTypes().getVideoAndImageTypesOnly())
538-
}
539-
listOf(AUDIO).containsAll(allowedTypes) -> {
540-
Pair(
541-
ChooserContext.AUDIO,
542-
MimeTypes().getAudioTypesOnly(mediaUtilsWrapper.getSitePlanForMimeTypes(site))
543-
)
544-
}
545-
else -> {
546-
Pair(
547-
ChooserContext.MEDIA_FILE,
548-
MimeTypes().getAllTypes(mediaUtilsWrapper.getSitePlanForMimeTypes(site))
549-
)
550-
}
551-
}
552-
OpenSystemPicker(context, types.toList(), canMultiselect)
539+
val chooserTypes = systemPickerResolver.resolveChooserContext(icon.allowedTypes, site)
540+
OpenSystemPicker(chooserTypes.context, chooserTypes.mimeTypes, canMultiselect)
553541
}
554542
is CapturePhoto -> OpenCameraForPhotos
555543
is SwitchSource -> {
@@ -606,6 +594,18 @@ class MediaPickerViewModel @Inject constructor(
606594
clickIcon(icon)
607595
}
608596

597+
/**
598+
* Opens the system picker with a narrowed set of allowed types after the user picks a category
599+
* (e.g. "Photos and videos" vs "Other files") from the disambiguation menu. This is the point at
600+
* which the device library is actually opened, so the open is tracked here rather than when the
601+
* disambiguation menu was shown.
602+
*/
603+
fun onSystemPickerTypeChosen(allowedTypes: Set<MediaType>) {
604+
val icon = ChooseFromAndroidDevice(allowedTypes)
605+
mediaPickerTracker.trackIconClick(icon, mediaPickerSetup)
606+
navigateForIcon(icon)
607+
}
608+
609609
private fun getRequiredPermissionsNames(): String {
610610
val permissionName = when {
611611
Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU -> R.string.permission_storage
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package org.wordpress.android.ui.mediapicker
2+
3+
import org.wordpress.android.fluxc.model.SiteModel
4+
import org.wordpress.android.fluxc.utils.MimeTypes
5+
import org.wordpress.android.ui.mediapicker.MediaPickerFragment.ChooserContext
6+
import org.wordpress.android.ui.mediapicker.MediaType.AUDIO
7+
import org.wordpress.android.ui.mediapicker.MediaType.DOCUMENT
8+
import org.wordpress.android.ui.mediapicker.MediaType.IMAGE
9+
import org.wordpress.android.ui.mediapicker.MediaType.VIDEO
10+
import org.wordpress.android.util.MediaUtilsWrapper
11+
import javax.inject.Inject
12+
13+
/**
14+
* Resolves how the "Choose from device" action should open the OS picker for a given set of allowed
15+
* media types: which [ChooserContext] to use, the MIME types to request, and whether the selection
16+
* is ambiguous (mixes visual media with other files) and therefore needs a disambiguation step.
17+
*/
18+
class SystemPickerResolver @Inject constructor(
19+
private val mediaUtilsWrapper: MediaUtilsWrapper
20+
) {
21+
private val mimeTypes = MimeTypes()
22+
23+
/**
24+
* True when the selection allows both visual media (images/videos) and non-visual files
25+
* (audio/documents). Android's Photo Picker only surfaces visual media, so the user is asked
26+
* which kind they want before a picker is opened.
27+
*/
28+
fun isAmbiguousMediaAndFileSelection(allowedTypes: Set<MediaType>): Boolean {
29+
val hasVisualMedia = allowedTypes.any { it == IMAGE || it == VIDEO }
30+
val hasOtherFiles = allowedTypes.any { it == AUDIO || it == DOCUMENT }
31+
return hasVisualMedia && hasOtherFiles
32+
}
33+
34+
/**
35+
* Maps [allowedTypes] to the [ChooserContext] and MIME type list to hand to the OS picker.
36+
*/
37+
fun resolveChooserContext(allowedTypes: Set<MediaType>, site: SiteModel?): ChooserTypes {
38+
val (context, types) = when {
39+
// Visual-media contexts use broad wildcards rather than our explicit accepted-subtype
40+
// list: on Android 13+ these route to the system Photo Picker, which filters album/cloud
41+
// contents by an exact match against EXTRA_MIME_TYPES. An explicit list (image/jpeg,
42+
// image/heic, ...) makes Google Photos albums appear empty because cloud items may not
43+
// report a matching subtype, so image/* and video/* are used to show all visual media.
44+
listOf(IMAGE).containsAll(allowedTypes) -> {
45+
ChooserContext.PHOTO to listOf(MIME_TYPE_IMAGE_ALL)
46+
}
47+
listOf(VIDEO).containsAll(allowedTypes) -> {
48+
ChooserContext.VIDEO to listOf(MIME_TYPE_VIDEO_ALL)
49+
}
50+
listOf(IMAGE, VIDEO).containsAll(allowedTypes) -> {
51+
ChooserContext.PHOTO_OR_VIDEO to listOf(MIME_TYPE_IMAGE_ALL, MIME_TYPE_VIDEO_ALL)
52+
}
53+
listOf(AUDIO).containsAll(allowedTypes) -> {
54+
ChooserContext.AUDIO to mimeTypes.getAudioTypesOnly(planFor(site)).toList()
55+
}
56+
else -> {
57+
ChooserContext.MEDIA_FILE to mimeTypes.getAllTypes(planFor(site)).toList()
58+
}
59+
}
60+
return ChooserTypes(context, types)
61+
}
62+
63+
private fun planFor(site: SiteModel?) = mediaUtilsWrapper.getSitePlanForMimeTypes(site)
64+
65+
data class ChooserTypes(val context: ChooserContext, val mimeTypes: List<String>)
66+
67+
companion object {
68+
private const val MIME_TYPE_IMAGE_ALL = "image/*"
69+
private const val MIME_TYPE_VIDEO_ALL = "video/*"
70+
}
71+
}

WordPress/src/main/java/org/wordpress/android/ui/posts/editor/EditorPhotoPicker.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,10 @@ class EditorPhotoPicker(
291291
else -> { /* Device is handled by OpenSystemPicker */ }
292292
}
293293
}
294+
is MediaPickerAction.ShowSystemPickerTypeMenu -> {
295+
// Only reachable when a flow allows both visual media and other files; the editor's
296+
// embedded picker relies upon other flows, so this never fires here.
297+
}
294298
}
295299
}
296300

WordPress/src/main/java/org/wordpress/android/util/WPMediaUtils.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,8 +261,12 @@ private static Intent prepareVideoLibraryIntent(Context context, boolean multiSe
261261
}
262262

263263
private static Intent prepareMediaLibraryIntent(Context context, boolean multiSelect) {
264+
// Use broad wildcards rather than our explicit accepted-subtype list: on Android 13+ this
265+
// ACTION_GET_CONTENT routes to the system Photo Picker, which filters album/cloud contents by
266+
// an exact match against EXTRA_MIME_TYPES. An explicit list (image/jpeg, image/heic, ...) makes
267+
// Google Photos albums appear empty because cloud items may not report a matching subtype.
264268
return prepareIntent(context, multiSelect, Intent.ACTION_GET_CONTENT, "*/*",
265-
new MimeTypes().getVideoAndImageTypesOnly(), R.string.pick_media);
269+
new String[]{"image/*", "video/*"}, R.string.pick_media);
266270
}
267271

268272
private static Intent prepareIntent(Context context, boolean multiSelect, String action, String intentType,

WordPress/src/main/res/values/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3296,6 +3296,8 @@
32963296
<string name="photo_picker_choose_photo">Choose photo from device</string>
32973297
<string name="photo_picker_choose_video">Choose video from device</string>
32983298
<string name="photo_picker_choose_file">Choose from device</string>
3299+
<string name="photo_picker_choose_photo_or_video">Photos and videos</string>
3300+
<string name="photo_picker_choose_other_files">Other files</string>
32993301
<string name="photo_picker_choose_audio">Choose audio from device</string>
33003302
<string name="photo_picker_capture_photo">Take photo</string>
33013303
<string name="photo_picker_capture_video">Take video</string>

0 commit comments

Comments
 (0)