Snap for 9275205 from 7cb5295d30abbb75097e991fc685fd7108e98903 to mainline-conscrypt-release
Change-Id: I5aabbc7d3d3c570fd7c6d829882721d4ee2f7692
diff --git a/Android.bp b/Android.bp
index 799edde..7a8824c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -26,6 +26,7 @@
"androidx.vectordrawable_vectordrawable-animated",
"androidx.exifinterface_exifinterface",
"exoplayer-mediaprovider-ui",
+ "modules-utils-shell-command-handler",
],
libs: [
@@ -151,3 +152,8 @@
src: "preinstalled-packages-com.android.providers.media.module.xml",
sub_dir: "sysconfig",
}
+
+sh_binary {
+ name: "media_provider",
+ src: "cli/media_provider_cli_wrapper.sh",
+}
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index a369c3c..c2d850d 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -135,6 +135,12 @@
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE" />
+ <service
+ android:name=
+ "com.android.providers.media.stableuris.job.StableUriIdleMaintenanceService"
+ android:exported="true"
+ android:permission="android.permission.BIND_JOB_SERVICE"/>
+
<service android:name="com.android.providers.media.fuse.ExternalStorageServiceImpl"
android:exported="true"
android:permission="android.permission.BIND_EXTERNAL_STORAGE_SERVICE">
diff --git a/apex/Android.bp b/apex/Android.bp
index ccc26f5..1544c37 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -14,6 +14,10 @@
apex_defaults {
name: "com.android.mediaprovider-defaults",
bootclasspath_fragments: ["com.android.mediaprovider-bootclasspath-fragment"],
+ sh_binaries: [
+ // MediaProvider CLI (cli/media_provider_cli_wrapper.sh)
+ "media_provider"
+ ],
prebuilts: [
"current_sdkinfo",
"privapp_allowlist_com.android.providers.media.module.xml"
diff --git a/apex/framework/java/android/provider/MediaStore.java b/apex/framework/java/android/provider/MediaStore.java
index e344c50..5c6e0b5 100644
--- a/apex/framework/java/android/provider/MediaStore.java
+++ b/apex/framework/java/android/provider/MediaStore.java
@@ -72,6 +72,8 @@
import androidx.annotation.RequiresApi;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -271,6 +273,28 @@
/** {@hide} */
public static final String USES_FUSE_PASSTHROUGH_RESULT = "uses_fuse_passthrough_result";
+ /**
+ * Only used for testing.
+ * {@hide}
+ */
+ @VisibleForTesting
+ public static final String RUN_IDLE_MAINTENANCE_FOR_STABLE_URIS =
+ "idle_maintenance_for_stable_uris";
+
+ /**
+ * Only used for testing.
+ * {@hide}
+ */
+ @VisibleForTesting
+ public static final String READ_BACKED_UP_FILE_PATHS = "read_backed_up_file_paths";
+
+ /**
+ * Only used for testing.
+ * {@hide}
+ */
+ @VisibleForTesting
+ public static final String DELETE_BACKED_UP_FILE_PATHS = "delete_backed_up_file_paths";
+
/** {@hide} */
public static final String QUERY_ARG_LIMIT = ContentResolver.QUERY_ARG_LIMIT;
/** {@hide} */
@@ -4637,6 +4661,36 @@
}
/**
+ * Only used for testing.
+ * {@hide}
+ */
+ @VisibleForTesting
+ public static void runIdleMaintenanceForStableUris(@NonNull ContentResolver resolver) {
+ resolver.call(AUTHORITY, RUN_IDLE_MAINTENANCE_FOR_STABLE_URIS, null, null);
+ }
+
+ /**
+ * Only used for testing.
+ * {@hide}
+ */
+ @VisibleForTesting
+ public static String[] readBackedUpFilePaths(@NonNull ContentResolver resolver,
+ String volumeName) {
+ Bundle bundle = resolver.call(AUTHORITY, READ_BACKED_UP_FILE_PATHS, volumeName, null);
+ return bundle.getStringArray(READ_BACKED_UP_FILE_PATHS);
+ }
+
+ /**
+ * Only used for testing.
+ * {@hide}
+ */
+ @VisibleForTesting
+ public static void deleteBackedUpFilePaths(@NonNull ContentResolver resolver,
+ String volumeName) {
+ resolver.call(AUTHORITY, DELETE_BACKED_UP_FILE_PATHS, volumeName, null);
+ }
+
+ /**
* Block until any pending operations have finished, such as
* {@link #scanFile} or {@link #scanVolume} requests.
*
diff --git a/cli/README.md b/cli/README.md
new file mode 100644
index 0000000..9ff12fe
--- /dev/null
+++ b/cli/README.md
@@ -0,0 +1,26 @@
+`media_provider_cli_wrapper.sh` is a thin wrapper script that exposes MediaProvider CLI.
+It's meant to be used similarly to other on-device shell binaries that expose CLIs to Android system
+services, such as `am`, `pm`, `wm`, `ime` etc.
+
+For example:
+```shell
+adb shell media_provider version
+```
+
+On device `media_provider` binary is found in `/apex/com.android.mediaprovider/bin/media_provider`,
+which, at the moment, is NOT included in `$PATH`, so in order to run `media_provider` you need to
+provide the full path to the binary, e.g.:
+```shell
+adb shell /apex/com.android.mediaprovider/bin/media_provider version
+```
+
+If you find yourself using `media_provider` often you may consider settings up an alias, e.g.:
+```shell
+alias amp="adb shell /apex/com.android.mediaprovider/bin/media_provider"
+```
+or
+```shell
+adb root
+adb remount
+adb shell ln -s -t /system/bin /apex/com.android.mediaprovider/bin/media_provider
+```
diff --git a/cli/media_provider_cli_wrapper.sh b/cli/media_provider_cli_wrapper.sh
new file mode 100644
index 0000000..659467f
--- /dev/null
+++ b/cli/media_provider_cli_wrapper.sh
@@ -0,0 +1,24 @@
+#!/system/bin/sh
+# First: join all arguments with '+' as delimiter
+#
+# For example: if this was run as `media_provider method arg1 arg2`, the `cmd` variable below
+# would be `method+arg1+arg2`
+
+old_ifs=$IFS
+IFS='+'
+cmd=$(echo "$*")
+IFS=$old_ifs
+
+# Second: do `content read`.
+#
+# It may look like `content call` could be a better fit, but it's actually not the case:
+# `content call` does not allow us to redirect the output of the command to the out FS (even
+# though android.os.Bundle can hold (Parcelable) FDs com.android.commands.content.Content can't
+# handle it).
+# See: http://cs/android-internal/frameworks/base/cmds/content/src/com/android/commands/content/Content.java;l=303;rcl=b3370acc279c39e98823a2dbb9835fe0db615579
+#
+# `content read`, on the other hand, nicely copies content of the FD receives from the
+# ContentProvider to the System.out.
+# See: http://cs/android-internal/frameworks/base/cmds/content/src/com/android/commands/content/Content.java;l=630;rcl=b3370acc279c39e98823a2dbb9835fe0db615579
+
+content read --uri content://media/cli?cmd="$cmd"
diff --git a/jni/FuseDaemon.cpp b/jni/FuseDaemon.cpp
index 3228521..5adf249 100644
--- a/jni/FuseDaemon.cpp
+++ b/jni/FuseDaemon.cpp
@@ -123,6 +123,9 @@
static constexpr char TRANSFORM_SYNTHETIC_DIR[] = "synthetic";
static constexpr char TRANSFORM_TRANSCODE_DIR[] = "transcode";
static constexpr char PRIMARY_VOLUME_PREFIX[] = "/storage/emulated";
+static constexpr char STORAGE_PREFIX[] = "/storage";
+
+static constexpr char INTERNAL[] = "internal";
static constexpr char FUSE_BPF_PROG_PATH[] = "/sys/fs/bpf/prog_fuse_media_fuse_media";
@@ -2437,7 +2440,7 @@
}
void FuseDaemon::DeleteFromLevelDb(const std::string& key) {
- if (!android::base::StartsWith(key, "/storage")) {
+ if (!android::base::StartsWith(key, STORAGE_PREFIX) && CheckLevelDbConnectionForInternal()) {
leveldb::Status status;
status = fuse->internal_level_db->Delete(leveldb::WriteOptions(), key);
if (!status.ok()) {
@@ -2447,7 +2450,7 @@
}
void FuseDaemon::InsertInLevelDb(const std::string& key, const std::string& value) {
- if (!android::base::StartsWith(key, "/storage")) {
+ if (!android::base::StartsWith(key, STORAGE_PREFIX) && CheckLevelDbConnectionForInternal()) {
leveldb::Status status;
status = fuse->internal_level_db->Put(leveldb::WriteOptions(), key, value);
if (!status.ok()) {
@@ -2464,7 +2467,8 @@
int counter = 0;
std::vector<std::string> file_paths;
- if (android::base::EqualsIgnoreCase(volume_name, "internal")) {
+ if (android::base::EqualsIgnoreCase(volume_name, INTERNAL) &&
+ CheckLevelDbConnectionForInternal()) {
leveldb::Iterator* it = fuse->internal_level_db->NewIterator(leveldb::ReadOptions());
if (android::base::EqualsIgnoreCase(last_read_value, "")) {
it->SeekToFirst();
@@ -2485,7 +2489,8 @@
std::string FuseDaemon::ReadBackedUpDataFromLevelDb(const std::string& filePath) {
std::string data = "";
- if (!android::base::StartsWithIgnoreCase(filePath, "/storage")) {
+ if (!android::base::StartsWithIgnoreCase(filePath, STORAGE_PREFIX) &&
+ CheckLevelDbConnectionForInternal()) {
leveldb::Status status =
fuse->internal_level_db->Get(leveldb::ReadOptions(), filePath, &data);
if (!status.ok()) {
@@ -2497,5 +2502,13 @@
return data;
}
+bool FuseDaemon::CheckLevelDbConnectionForInternal() {
+ if (fuse->internal_level_db == nullptr) {
+ LOG(ERROR) << "Leveldb setup is missing for internal";
+ return false;
+ }
+ return true;
+}
+
} //namespace fuse
} // namespace mediaprovider
diff --git a/jni/FuseDaemon.h b/jni/FuseDaemon.h
index dea8859..c285167 100644
--- a/jni/FuseDaemon.h
+++ b/jni/FuseDaemon.h
@@ -99,6 +99,11 @@
*/
std::string ReadBackedUpDataFromLevelDb(const std::string& filePath);
+ /*
+ * Returns true if level db setup exists for internal.
+ */
+ bool CheckLevelDbConnectionForInternal();
+
private:
FuseDaemon(const FuseDaemon&) = delete;
void operator=(const FuseDaemon&) = delete;
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index e8ebbcd..fdddf38 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Laat toe"</string>
<string name="deny" msgid="6040983710442068936">"Weier"</string>
<string name="picker_browse" msgid="5554477454636075934">"Blaai …"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Instellings"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Wolkmedia-app"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Deel foto\'s en video\'s wat jy van ander dienste af in die Android Fotokieser rugsteun"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Kry toegang tot wolkmedia vanaf"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Geen"</string>
<string name="add" msgid="2894574044585549298">"Voeg by"</string>
<string name="deselect" msgid="4297825044827769490">"Ontkies"</string>
<string name="deselected" msgid="8488133193326208475">"Ontkies"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 66daa3a..388502e 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"ፍቀድ"</string>
<string name="deny" msgid="6040983710442068936">"ከልክል"</string>
<string name="picker_browse" msgid="5554477454636075934">"ያስሱ…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"ቅንብሮች"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"የደመና ሚዲያ መተግበሪያ"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"በAndroid Photopicker ውስጥ እርስዎ ከሌሎች አገልግሎቶች ምትክ የሚያስቀምጡላቸውን ፎቶዎች እና ቪድዮዎች ያጋሩ"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"የደመና ሚዲያን ይድረሱ ከ"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"ምንም"</string>
<string name="add" msgid="2894574044585549298">"አክል"</string>
<string name="deselect" msgid="4297825044827769490">"አትምረጥ"</string>
<string name="deselected" msgid="8488133193326208475">"አልተመረጠም"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 3ec2735..195e9f3 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"سماح"</string>
<string name="deny" msgid="6040983710442068936">"رفض"</string>
<string name="picker_browse" msgid="5554477454636075934">"جارٍ التصفّح..."</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"الإعدادات"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"تطبيق الوسائط في السحابة الإلكترونية"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"يمكنك استخدام Android Photopicker لمشاركة الصور والفيديوهات التي تحتفظ بنسخة احتياطية منها من الخدمات الأخرى."</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"الوصول إلى الوسائط في السحابة الإلكترونية من"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"بلا تطبيق"</string>
<string name="add" msgid="2894574044585549298">"إضافة"</string>
<string name="deselect" msgid="4297825044827769490">"إلغاء الاختيار"</string>
<string name="deselected" msgid="8488133193326208475">"تم إلغاء الاختيار"</string>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index 5a116ea..6535241 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"অনুমতি দিয়ক"</string>
<string name="deny" msgid="6040983710442068936">"অস্বীকাৰ কৰক"</string>
<string name="picker_browse" msgid="5554477454636075934">"ব্ৰাউজ কৰক…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"ছেটিং"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"ক্লাউড মিডিয়া এপ্"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"আপুনি অন্য সেৱাসমূহৰ পৰা বেক আপ লোৱা ফট’ আৰু ভিডিঅ’সমূহ Android Photopickerত শ্বেয়াৰ কৰক"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"ইয়াৰ পৰা ক্লাউড মিডিয়া এক্সেছ কৰক"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"নাই"</string>
<string name="add" msgid="2894574044585549298">"যোগ দিয়ক"</string>
<string name="deselect" msgid="4297825044827769490">"বাছনিৰ পৰা আঁতৰাওক"</string>
<string name="deselected" msgid="8488133193326208475">"বাছনিৰ পৰা আঁতৰোৱা হ’ল"</string>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 0611007..a905536 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"İcazə verin"</string>
<string name="deny" msgid="6040983710442068936">"Rədd edin"</string>
<string name="picker_browse" msgid="5554477454636075934">"Gözdən keçirin…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Ayarlar"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Bulud media tətbiqi"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Android Fotoseçicidə digər xidmətlərdən yedəklədiyiniz foto və videoları paylaşın"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Bulud mediasına buradan giriş edin:"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Heç bir"</string>
<string name="add" msgid="2894574044585549298">"Əlavə edin"</string>
<string name="deselect" msgid="4297825044827769490">"Seçimi ləğv edin"</string>
<string name="deselected" msgid="8488133193326208475">"Seçimi ləğv edilib"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index a1ddaed..f077d22 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Dozvoli"</string>
<string name="deny" msgid="6040983710442068936">"Odbij"</string>
<string name="picker_browse" msgid="5554477454636075934">"Pregledaj…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Podešavanja"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Aplikacija za medije u klaudu"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Delite slike i video snimke za koje pravite rezervne kopije iz drugih usluga u Android biraču slika"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Pristupajte medijima u klaudu iz"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Ništa"</string>
<string name="add" msgid="2894574044585549298">"Dodaj"</string>
<string name="deselect" msgid="4297825044827769490">"Opozovi izbor"</string>
<string name="deselected" msgid="8488133193326208475">"Opozvan je izbor"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index c025281..b12c9ae 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Дазволіць"</string>
<string name="deny" msgid="6040983710442068936">"Адмовіць"</string>
<string name="picker_browse" msgid="5554477454636075934">"Прагляд…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Налады"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Воблачная мультымедыйная праграма"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Дзякуючы інструменту выбару фота на Android вы можаце хутка абагуліць фота і відэа, рэзервовыя копіі якіх створаны ў іншых сэрвісах"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Доступ да воблачных мультымедыя з:"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Няма"</string>
<string name="add" msgid="2894574044585549298">"Дадаць"</string>
<string name="deselect" msgid="4297825044827769490">"Адмяніць выбар"</string>
<string name="deselected" msgid="8488133193326208475">"Выбар скасаваны"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 002bea2..64b123f 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Разрешаване"</string>
<string name="deny" msgid="6040983710442068936">"Отказ"</string>
<string name="picker_browse" msgid="5554477454636075934">"Преглед…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Настройки"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Приложение за мултимедия в облака"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Инструментът на Android за избор на снимки ви дава възможност да споделяте изображения и видеоклипове, на които създавате резервни копия от други услуги"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Достъп до мултимедия в облака от"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Няма"</string>
<string name="add" msgid="2894574044585549298">"Добавяне"</string>
<string name="deselect" msgid="4297825044827769490">"Премахване на избора"</string>
<string name="deselected" msgid="8488133193326208475">"Неизбрано"</string>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 36a5281..8525d48 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"অনুমতি দিন"</string>
<string name="deny" msgid="6040983710442068936">"বাতিল করুন"</string>
<string name="picker_browse" msgid="5554477454636075934">"ব্রাউজ করুন…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"সেটিংস"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"ক্লাউড মিডিয়া অ্যাপ"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Android ফটোপিকার টুলে অন্যান্য পরিষেবা থেকে ব্যাক-আপ নেওয়া ফটো ও ভিডিও শেয়ার করুন"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"এখান থেকে ক্লাউড মিডিয়া অ্যাক্সেস করুন"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"কোনওটিই নয়"</string>
<string name="add" msgid="2894574044585549298">"যোগ করুন"</string>
<string name="deselect" msgid="4297825044827769490">"টিক চিহ্নটি সরিয়ে দিন"</string>
<string name="deselected" msgid="8488133193326208475">"টিকচিহ্ন সরিয়ে দিন"</string>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 9366c2c..318685f 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Dozvoli"</string>
<string name="deny" msgid="6040983710442068936">"Odbij"</string>
<string name="picker_browse" msgid="5554477454636075934">"Pregledajte…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Postavke"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Aplikacija za medijske sadržaje u oblaku"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Dijelite fotografije i videozapise čije sigurnosne kopije napravite s drugih usluga u Android Photopickeru"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Pristupite medijskom sadržaju u oblaku iz"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Ništa"</string>
<string name="add" msgid="2894574044585549298">"Dodaj"</string>
<string name="deselect" msgid="4297825044827769490">"Poništi odabir"</string>
<string name="deselected" msgid="8488133193326208475">"Odabir poništen"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index ed844b0..88cedac 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Permet"</string>
<string name="deny" msgid="6040983710442068936">"Denega"</string>
<string name="picker_browse" msgid="5554477454636075934">"Navega…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Configuració"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Aplicació multimèdia al núvol"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Comparteix fotos i vídeos des d\'una còpia de seguretat d\'altres serveis d\'Android Photopicker"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Accedeix al contingut multimèdia al núvol des de"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Cap"</string>
<string name="add" msgid="2894574044585549298">"Afegeix"</string>
<string name="deselect" msgid="4297825044827769490">"Desselecciona"</string>
<string name="deselected" msgid="8488133193326208475">"Desseleccionat"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 1c1a9c3..cecefc9 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Povolit"</string>
<string name="deny" msgid="6040983710442068936">"Zakázat"</string>
<string name="picker_browse" msgid="5554477454636075934">"Procházet…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Nastavení"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Aplikace pro cloudová média"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Sdílet v nástroji Android Photopicker fotografie a videa zálohovaná z jiných služeb"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Přístup ke cloudovým médiím z"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Žádný"</string>
<string name="add" msgid="2894574044585549298">"Přidat"</string>
<string name="deselect" msgid="4297825044827769490">"Zrušit výběr"</string>
<string name="deselected" msgid="8488133193326208475">"Výběr zrušen"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 6afdecf..5e83475 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Tillad"</string>
<string name="deny" msgid="6040983710442068936">"Afvis"</string>
<string name="picker_browse" msgid="5554477454636075934">"Gennemse…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Indstillinger"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Skymedieapp"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Del billeder og videoer, som du sikkerhedskopierer fra andre tjenester, i Android Photopicker"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Få adgang til medier i skyen via"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Ingen"</string>
<string name="add" msgid="2894574044585549298">"Tilføj"</string>
<string name="deselect" msgid="4297825044827769490">"Fravælg"</string>
<string name="deselected" msgid="8488133193326208475">"Fravalgt"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 7ae3df2..2d301b7 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Zulassen"</string>
<string name="deny" msgid="6040983710442068936">"Ablehnen"</string>
<string name="picker_browse" msgid="5554477454636075934">"Stöbern…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Einstellungen"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Cloud-Medien-App"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Mit der Bildauswahl von Android kannst du Fotos und Videos teilen, die du über andere Dienste gesichert hast"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Zugriff auf Cloud-Medien aus"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Keine"</string>
<string name="add" msgid="2894574044585549298">"Hinzufügen"</string>
<string name="deselect" msgid="4297825044827769490">"Auswahl aufheben"</string>
<string name="deselected" msgid="8488133193326208475">"Auswahl aufgehoben"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 1cddb45..e8831f6 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Να επιτρέπεται"</string>
<string name="deny" msgid="6040983710442068936">"Απόρριψη"</string>
<string name="picker_browse" msgid="5554477454636075934">"Περιήγηση…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Ρυθμίσεις"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Εφαρμογή μέσων στο cloud"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Μοιραστείτε φωτογραφίες και βίντεο για τα οποία δημιουργείτε αντίγραφα ασφαλείας από άλλες υπηρεσίες στο Android Photopicker"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Πρόσβαση σε μέσα στο cloud από"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Καμία"</string>
<string name="add" msgid="2894574044585549298">"Προσθήκη"</string>
<string name="deselect" msgid="4297825044827769490">"Αποεπιλογή"</string>
<string name="deselected" msgid="8488133193326208475">"Αποεπιλέχθηκε"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 79ce2c2..8b06f4c 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Allow"</string>
<string name="deny" msgid="6040983710442068936">"Deny"</string>
<string name="picker_browse" msgid="5554477454636075934">"Browse…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Settings"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Cloud media app"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Share photos and videos that you back up from other services in the Android Photopicker"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Access cloud media from"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"None"</string>
<string name="add" msgid="2894574044585549298">"Add"</string>
<string name="deselect" msgid="4297825044827769490">"Deselect"</string>
<string name="deselected" msgid="8488133193326208475">"Deselected"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index 79ce2c2..8b06f4c 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Allow"</string>
<string name="deny" msgid="6040983710442068936">"Deny"</string>
<string name="picker_browse" msgid="5554477454636075934">"Browse…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Settings"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Cloud media app"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Share photos and videos that you back up from other services in the Android Photopicker"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Access cloud media from"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"None"</string>
<string name="add" msgid="2894574044585549298">"Add"</string>
<string name="deselect" msgid="4297825044827769490">"Deselect"</string>
<string name="deselected" msgid="8488133193326208475">"Deselected"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 79ce2c2..8b06f4c 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Allow"</string>
<string name="deny" msgid="6040983710442068936">"Deny"</string>
<string name="picker_browse" msgid="5554477454636075934">"Browse…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Settings"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Cloud media app"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Share photos and videos that you back up from other services in the Android Photopicker"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Access cloud media from"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"None"</string>
<string name="add" msgid="2894574044585549298">"Add"</string>
<string name="deselect" msgid="4297825044827769490">"Deselect"</string>
<string name="deselected" msgid="8488133193326208475">"Deselected"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 79ce2c2..8b06f4c 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Allow"</string>
<string name="deny" msgid="6040983710442068936">"Deny"</string>
<string name="picker_browse" msgid="5554477454636075934">"Browse…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Settings"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Cloud media app"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Share photos and videos that you back up from other services in the Android Photopicker"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Access cloud media from"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"None"</string>
<string name="add" msgid="2894574044585549298">"Add"</string>
<string name="deselect" msgid="4297825044827769490">"Deselect"</string>
<string name="deselected" msgid="8488133193326208475">"Deselected"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 6636cc0..e1a44e3 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Permitir"</string>
<string name="deny" msgid="6040983710442068936">"Rechazar"</string>
<string name="picker_browse" msgid="5554477454636075934">"Explorar…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Configuración"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Aplicación multimedia en la nube"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Comparte las fotos y los vídeos de los que hayas creado una copia de seguridad desde otros servicios en el Photopicker de Android"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Accede a los medios en la nube desde"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Ninguna"</string>
<string name="add" msgid="2894574044585549298">"Agregar"</string>
<string name="deselect" msgid="4297825044827769490">"Anular la selección"</string>
<string name="deselected" msgid="8488133193326208475">"Sin seleccionar"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 8dbb8bc..cf07eb3 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Permitir"</string>
<string name="deny" msgid="6040983710442068936">"Denegar"</string>
<string name="picker_browse" msgid="5554477454636075934">"Buscar…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Ajustes"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Aplicación multimedia en la nube"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Comparte las fotos y los vídeos de los que hayas creado una copia de seguridad desde otros servicios en el selector de fotos de Android"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Accede al contenido multimedia en la nube desde"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Ninguna"</string>
<string name="add" msgid="2894574044585549298">"Añadir"</string>
<string name="deselect" msgid="4297825044827769490">"Desmarcar"</string>
<string name="deselected" msgid="8488133193326208475">"Desmarcado"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index b022ce3..503cf05 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Luba"</string>
<string name="deny" msgid="6040983710442068936">"Keela"</string>
<string name="picker_browse" msgid="5554477454636075934">"Sirvimine …"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Seaded"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Pilvemeediarakendus"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Jagage Androidi fotovalijas fotosid ja videoid, mida varundate muudest teenustest"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Pilvemeediarakendus:"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Pole"</string>
<string name="add" msgid="2894574044585549298">"Lisa"</string>
<string name="deselect" msgid="4297825044827769490">"Tühista valik"</string>
<string name="deselected" msgid="8488133193326208475">"Valik on tühistatud"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 8fb05d3..4219520 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Eman baimena"</string>
<string name="deny" msgid="6040983710442068936">"Ukatu"</string>
<string name="picker_browse" msgid="5554477454636075934">"Arakatu…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Ezarpenak"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Hodeiko multimedia-aplikazioa"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Partekatu beste zerbitzu batzuetako argazkien eta bideoen babeskopiak Android-en argazki-hautatzailean"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Atzitu honen bidez gordetako hodeiko multimedia-edukia:"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Bat ere ez"</string>
<string name="add" msgid="2894574044585549298">"Gehitu"</string>
<string name="deselect" msgid="4297825044827769490">"Desautatu"</string>
<string name="deselected" msgid="8488133193326208475">"Desautatuta"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index b8cc0c6..677820b 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"اجازه دادن"</string>
<string name="deny" msgid="6040983710442068936">"مجاز نبودن"</string>
<string name="picker_browse" msgid="5554477454636075934">"مرور کردن…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"تنظیمات"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"برنامه رسانه ابری"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"عکسها و ویدیوهایی که از سرویسهای دیگر پشتیبانگیری میکنید در «انتخابگر عکس Android» همرسانی میشود"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"دسترسی به رسانه ابری از"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"هیچکدام"</string>
<string name="add" msgid="2894574044585549298">"افزودن"</string>
<string name="deselect" msgid="4297825044827769490">"لغو انتخاب"</string>
<string name="deselected" msgid="8488133193326208475">"لغو انتخابشده"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 87fd871..3f1acdd 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Salli"</string>
<string name="deny" msgid="6040983710442068936">"Estä"</string>
<string name="picker_browse" msgid="5554477454636075934">"Selaa…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Asetukset"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Pilvimediasovellus"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Jaa muista palveluista varmuuskopioidut kuvat ja videot Androidin Kuvien valitsimessa"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Pääsy pilvimediaan:"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"–"</string>
<string name="add" msgid="2894574044585549298">"Lisää"</string>
<string name="deselect" msgid="4297825044827769490">"Poista valinta"</string>
<string name="deselected" msgid="8488133193326208475">"Valinta poistettu"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 5ea2834..3d52f25 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Autoriser"</string>
<string name="deny" msgid="6040983710442068936">"Refuser"</string>
<string name="picker_browse" msgid="5554477454636075934">"Parcourir…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Paramètres"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Application multimédia infonuagique"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Partagez des photos et des vidéos que vous sauvegardez à partir d\'autres services dans Android Photopicker"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Accéder au contenu multimédia infonuagique à partir de"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Aucune"</string>
<string name="add" msgid="2894574044585549298">"Ajouter"</string>
<string name="deselect" msgid="4297825044827769490">"Désélectionner"</string>
<string name="deselected" msgid="8488133193326208475">"Désélectionné"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 35e1b0b..b96cb86 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Autoriser"</string>
<string name="deny" msgid="6040983710442068936">"Refuser"</string>
<string name="picker_browse" msgid="5554477454636075934">"Parcourir…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Paramètres"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Appli multimédia cloud"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Partagez des photos et vidéos sauvegardées à partir d\'autres services dans le sélecteur de photos Android"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Accéder aux contenus multimédias cloud à partir de"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Aucune"</string>
<string name="add" msgid="2894574044585549298">"Ajouter"</string>
<string name="deselect" msgid="4297825044827769490">"Désélectionner"</string>
<string name="deselected" msgid="8488133193326208475">"Désélectionné"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 60d1ba4..572f801 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"મંજૂરી આપો"</string>
<string name="deny" msgid="6040983710442068936">"નકારો"</string>
<string name="picker_browse" msgid="5554477454636075934">"બ્રાઉઝ કરો…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"સેટિંગ"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"ક્લાઉડ મીડિયા ઍપ"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Android Photopickerમાં તમે અન્ય સેવાઓથી બૅકઅપ લો છો તે ફોટા અને વીડિયોને શેર કરો"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"આમાંથી ક્લાઉડ મીડિયાને ઍક્સેસ કરો"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"એકપણ નહીં"</string>
<string name="add" msgid="2894574044585549298">"ઉમેરો"</string>
<string name="deselect" msgid="4297825044827769490">"નાપસંદ કરો"</string>
<string name="deselected" msgid="8488133193326208475">"નાપસંદ કર્યું"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 5d07a37..742d011 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"अनुमति दें"</string>
<string name="deny" msgid="6040983710442068936">"अनुमति न दें"</string>
<string name="picker_browse" msgid="5554477454636075934">"ब्राउज़ करें…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"सेटिंग"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"क्लाउड मीडिया ऐप्लिकेशन"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Android में फ़ोटो पिकर की मदद से, उन फ़ोटो और वीडियो को शेयर करें जिनका बैक अप आपने अन्य सेवाओं पर लिया है."</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"क्लाउड पर मौजूद मीडिया को यहां से ऐक्सेस करें:"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"कोई नहीं"</string>
<string name="add" msgid="2894574044585549298">"जोड़ें"</string>
<string name="deselect" msgid="4297825044827769490">"चुना हुआ हटाएं"</string>
<string name="deselected" msgid="8488133193326208475">"चुना हुआ हटाया गया"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 4131441..ab37157 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Dopusti"</string>
<string name="deny" msgid="6040983710442068936">"Odbij"</string>
<string name="picker_browse" msgid="5554477454636075934">"Pregled…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Postavke"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Aplikacija za medijske sadržaje u oblaku"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Podijelite fotografije i videozapise koje sigurnosno kopirate s drugih usluga u Androidovom alatu za odabir fotografija"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Pristupi medijima u oblaku putem"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Ništa"</string>
<string name="add" msgid="2894574044585549298">"Dodaj"</string>
<string name="deselect" msgid="4297825044827769490">"Poništi odabir"</string>
<string name="deselected" msgid="8488133193326208475">"Odabir poništen"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 24a9615..dbfc347 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Engedélyezés"</string>
<string name="deny" msgid="6040983710442068936">"Tiltás"</string>
<string name="picker_browse" msgid="5554477454636075934">"Böngészés…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Beállítások"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Felhőbeli médiaalkalmazás"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Az Android Photopicker szolgáltatásban megoszthat olyan fotókat és videókat, amelyekről más alkalmazásokból készít biztonsági másolatot"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Hozzáférés a következő szolgáltatásban tárolt felhőbeli médiatartalmakhoz:"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Nincs"</string>
<string name="add" msgid="2894574044585549298">"Hozzáadás"</string>
<string name="deselect" msgid="4297825044827769490">"Jelölés törlése"</string>
<string name="deselected" msgid="8488133193326208475">"Kijelölés megszüntetve"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index af21180..a74f8e3 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Թույլատրել"</string>
<string name="deny" msgid="6040983710442068936">"Մերժել"</string>
<string name="picker_browse" msgid="5554477454636075934">"Դիտել…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Կարգավորումներ"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Ամպային մուլտիմեդիա հավելված"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Android-ի լուսանկարների ընտրիչի միջոցով կիսվեք լուսանկարներով և տեսանյութերով, որոնք պահուստավորում եք այլ ծառայություններում"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Օգտվեք ամպային մեդիա բովանդակությունից հետևյալ մատակարարից՝"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Չկա"</string>
<string name="add" msgid="2894574044585549298">"Ավելացնել"</string>
<string name="deselect" msgid="4297825044827769490">"Ապընտրել"</string>
<string name="deselected" msgid="8488133193326208475">"Ապընտրված"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 1186c5b..b974996 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Izinkan"</string>
<string name="deny" msgid="6040983710442068936">"Tolak"</string>
<string name="picker_browse" msgid="5554477454636075934">"Cari …"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Setelan"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Aplikasi media cloud"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Bagikan foto dan video yang Anda cadangkan dari layanan lainnya di Pemilih foto Android"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Akses media cloud dari"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Tidak ada"</string>
<string name="add" msgid="2894574044585549298">"Tambahkan"</string>
<string name="deselect" msgid="4297825044827769490">"Batalkan pilihan"</string>
<string name="deselected" msgid="8488133193326208475">"Batal dipilih"</string>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 0d9a46a..0dbf4ef 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Leyfa"</string>
<string name="deny" msgid="6040983710442068936">"Hafna"</string>
<string name="picker_browse" msgid="5554477454636075934">"Skoða…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Stillingar"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Efnisforrit í skýi"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Deildu myndum og myndskeiðum sem þú tekur afrit af í öðrum þjónustum í Android Photopicker"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Opna skýjaefni frá"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Ekkert"</string>
<string name="add" msgid="2894574044585549298">"Bæta við"</string>
<string name="deselect" msgid="4297825044827769490">"Afvelja"</string>
<string name="deselected" msgid="8488133193326208475">"Afvalið"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 0a0c152..65f1fd8 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Consenti"</string>
<string name="deny" msgid="6040983710442068936">"Rifiuta"</string>
<string name="picker_browse" msgid="5554477454636075934">"Sfoglia…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Impostazioni"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"App multimediale con funzionalità cloud"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Condividi foto e video di cui esegui il backup da altri servizi nel selettore di foto Android"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Accedi ai contenuti multimediali sul cloud da"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Nessuna"</string>
<string name="add" msgid="2894574044585549298">"Aggiungi"</string>
<string name="deselect" msgid="4297825044827769490">"Deseleziona"</string>
<string name="deselected" msgid="8488133193326208475">"Deselezionato"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 3137235..2dde30c 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"אישור"</string>
<string name="deny" msgid="6040983710442068936">"דחייה"</string>
<string name="picker_browse" msgid="5554477454636075934">"עיון…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"הגדרות"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"אפליקציית מדיה בענן"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"אפשר לשתף תמונות וסרטונים שגיבית משירותים אחרים בכלי לבחירת תמונות ב-Android"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"גישה למדיה בענן מתוך"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"ללא"</string>
<string name="add" msgid="2894574044585549298">"הוספה"</string>
<string name="deselect" msgid="4297825044827769490">"ביטול הבחירה"</string>
<string name="deselected" msgid="8488133193326208475">"הבחירה בוטלה"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 71d32ba..27b31f9 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"許可"</string>
<string name="deny" msgid="6040983710442068936">"許可しない"</string>
<string name="picker_browse" msgid="5554477454636075934">"参照…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"設定"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"クラウド メディア アプリ"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"他のサービスからバックアップした写真と動画を Android の写真選択ツールで共有できます"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"クラウド メディアへのアクセス元"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"なし"</string>
<string name="add" msgid="2894574044585549298">"追加"</string>
<string name="deselect" msgid="4297825044827769490">"選択を解除"</string>
<string name="deselected" msgid="8488133193326208475">"選択解除済み"</string>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index 711fee7..300309a 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"დაშვება"</string>
<string name="deny" msgid="6040983710442068936">"უარყოფა"</string>
<string name="picker_browse" msgid="5554477454636075934">"დათვალიერება…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"პარამეტრები"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"ღრუბლოვანი მედია აპი"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"გააზიარეთ ფოტოები და ვიდეოები, რომელთა სარეზერვო ასლები შექმნილი გაქვთ Android Photopicker-ის სხვა სერვისებიდან"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"ღრუბლოვან მედიაზე წვდომა აქედან:"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"არცერთი"</string>
<string name="add" msgid="2894574044585549298">"დამატება"</string>
<string name="deselect" msgid="4297825044827769490">"არჩევის გაუქმება"</string>
<string name="deselected" msgid="8488133193326208475">"არჩევა გაუქმებულია"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 06fe7bd..b534fde 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Рұқсат ету"</string>
<string name="deny" msgid="6040983710442068936">"Тыйым салу"</string>
<string name="picker_browse" msgid="5554477454636075934">"Шолу…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Параметрлер"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Бұлттық мультимедиа қолданбасы"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Басқа қызметтерде сақтық көшірмесін жасаған суреттер мен бейнелерді Android сурет таңдағыш құралында бөлісіңіз."</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Бұлттық мультимедиа қолданбасына келесі жерден кіріңіз:"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Жоқ"</string>
<string name="add" msgid="2894574044585549298">"Қосу"</string>
<string name="deselect" msgid="4297825044827769490">"Таңдамау"</string>
<string name="deselected" msgid="8488133193326208475">"Таңдау алынған"</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 2d517fb..acbe11e 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"អនុញ្ញាត"</string>
<string name="deny" msgid="6040983710442068936">"បដិសេធ"</string>
<string name="picker_browse" msgid="5554477454636075934">"រុករក…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"ការកំណត់"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"កម្មវិធីមេឌៀលើពពក"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"ចែករំលែករូបថត និងវីដេអូដែលអ្នកបម្រុងទុកពីសេវាកម្មផ្សេងទៀតនៅក្នុងផ្ទាំងជ្រើសរើសរូបថតរបស់ Android"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"ចូលប្រើប្រាស់មេឌៀលើពពកពី"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"គ្មាន"</string>
<string name="add" msgid="2894574044585549298">"បញ្ចូល"</string>
<string name="deselect" msgid="4297825044827769490">"ដកការជ្រើសរើស"</string>
<string name="deselected" msgid="8488133193326208475">"បានដកការជ្រើសរើស"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index b0f21c2..95f24d1 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"ಅನುಮತಿಸಿ"</string>
<string name="deny" msgid="6040983710442068936">"ನಿರಾಕರಿಸಿ"</string>
<string name="picker_browse" msgid="5554477454636075934">"ಬ್ರೌಸ್ ಮಾಡಿ…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"ಕ್ಲೌಡ್ ಮಾಧ್ಯಮ ಆ್ಯಪ್"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Android ಫೋಟೋ ಪಿಕರ್ನಲ್ಲಿ ಇತರ ಸೇವೆಗಳಿಂದ ನೀವು ಬ್ಯಾಕಪ್ ಮಾಡುವ ಫೋಟೋಗಳು ಮತ್ತು ವೀಡಿಯೊಗಳನ್ನು ಹಂಚಿಕೊಳ್ಳಿ"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"ಇದರಿಂದ ಕ್ಲೌಡ್ ಮಾಧ್ಯಮವನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"ಯಾವುದೂ ಅಲ್ಲ"</string>
<string name="add" msgid="2894574044585549298">"ಸೇರಿಸಿ"</string>
<string name="deselect" msgid="4297825044827769490">"ಆಯ್ಕೆ ರದ್ದುಮಾಡಿ"</string>
<string name="deselected" msgid="8488133193326208475">"ಆಯ್ಕೆ ರದ್ದುಮಾಡಲಾಗಿದೆ"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index b47c3fd..5a5714f 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"허용"</string>
<string name="deny" msgid="6040983710442068936">"거부"</string>
<string name="picker_browse" msgid="5554477454636075934">"찾아보기…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"설정"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"클라우드 미디어 앱"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"다른 서비스에서 백업한 사진과 동영상을 Android 사진 선택 도구에서 공유합니다."</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"클라우드 미디어 액세스 위치"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"없음"</string>
<string name="add" msgid="2894574044585549298">"추가"</string>
<string name="deselect" msgid="4297825044827769490">"선택 해제"</string>
<string name="deselected" msgid="8488133193326208475">"선택 해제됨"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 8ae7d10..2bd52d8 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Ооба"</string>
<string name="deny" msgid="6040983710442068936">"Жок"</string>
<string name="picker_browse" msgid="5554477454636075934">"Карап чыгуу…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Параметрлер"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Булуттагы мультимедиа колдонмосу"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Камдык көчүрмөсү башка кызматтарда сакталган сүрөттөр менен видеолорду Android Photopicker аркылуу бөлүшүү"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Төмөнкүдөн алынган булуттагы мультимедианы колдонуу:"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Жок"</string>
<string name="add" msgid="2894574044585549298">"Кошуу"</string>
<string name="deselect" msgid="4297825044827769490">"Тандоодон чыгаруу"</string>
<string name="deselected" msgid="8488133193326208475">"Тандоодон чыгарылды"</string>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index 76190e8..c09404a 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"ອະນຸຍາດ"</string>
<string name="deny" msgid="6040983710442068936">"ປະຕິເສດ"</string>
<string name="picker_browse" msgid="5554477454636075934">"ເລືອກເບິ່ງ…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"ການຕັ້ງຄ່າ"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"ແອັບມີເດຍໃນລະບົບຄລາວ"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"ແບ່ງປັນຮູບພາບ ແລະ ວິດີໂອທີ່ທ່ານສຳຮອງຂໍ້ມູນຈາກບໍລິການອື່ນໆໃນ Android Photopicker"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"ເຂົ້າເຖິງມີເດຍໃນລະບົບຄລາວຈາກ"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"ບໍ່ມີ"</string>
<string name="add" msgid="2894574044585549298">"ເພີ່ມ"</string>
<string name="deselect" msgid="4297825044827769490">"ເຊົາເລືອກ"</string>
<string name="deselected" msgid="8488133193326208475">"ເຊົາເລືອກແລ້ວ"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 773aa6a..8673de4 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Leisti"</string>
<string name="deny" msgid="6040983710442068936">"Atmesti"</string>
<string name="picker_browse" msgid="5554477454636075934">"Naršyti…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Nustatymai"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Medijos debesyje programa"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Naudodami „Android Photopicker“ bendrinkite nuotraukas ir vaizdo įrašus, kurių atsargines kopijas kuriate kitose paslaugose"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Pasiekti mediją debesyje iš"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Nėra"</string>
<string name="add" msgid="2894574044585549298">"Pridėti"</string>
<string name="deselect" msgid="4297825044827769490">"Panaikinti pasirinkimą"</string>
<string name="deselected" msgid="8488133193326208475">"Pasirinkimas panaikintas"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index c6241bc..02cd07d 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Atļaut"</string>
<string name="deny" msgid="6040983710442068936">"Neatļaut"</string>
<string name="picker_browse" msgid="5554477454636075934">"Pārlūkot…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Iestatījumi"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Mākoņa multivides lietotne"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Kopīgojiet no citiem pakalpojumiem dublētos fotoattēlus un videoklipus Android fotoattēlu atlasītājā."</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Piekļūstiet mākoņa multivides saturam no"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Nav"</string>
<string name="add" msgid="2894574044585549298">"Pievienot"</string>
<string name="deselect" msgid="4297825044827769490">"Noņemt atlasi"</string>
<string name="deselected" msgid="8488133193326208475">"Atlase noņemta"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index fd6606a..6b79166 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Дозволи"</string>
<string name="deny" msgid="6040983710442068936">"Одбиј"</string>
<string name="picker_browse" msgid="5554477454636075934">"Прелистувајте…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Поставки"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Апликација за аудиовизуелни содржини во облак"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Споделувајте фотографии и видеа од кои сте направиле бекап од други услуги во „Избирачот на фотографии на Android“"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Пристапете до аудиовизуелните содржини во облак од"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Нема"</string>
<string name="add" msgid="2894574044585549298">"Додај"</string>
<string name="deselect" msgid="4297825044827769490">"Поништи го изборот"</string>
<string name="deselected" msgid="8488133193326208475">"Изборот е поништен"</string>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 2d89f57..02f0766 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"അനുവദിക്കൂ"</string>
<string name="deny" msgid="6040983710442068936">"നിരസിക്കുക"</string>
<string name="picker_browse" msgid="5554477454636075934">"ബ്രൗസ് ചെയ്യുക…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"ക്രമീകരണം"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"ക്ലൗഡ് മീഡിയ ആക്സസ് ചെയ്യുക"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"മറ്റ് സേവനങ്ങളിൽ നിന്ന് നിങ്ങൾ ബാക്കപ്പ് ചെയ്യുന്ന ഫോട്ടോകളും വീഡിയോകളും Android Photopicker-ൽ പങ്കിടുക"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"ക്ലൗഡ് മീഡിയ ആപ്പിൽ നിന്ന്"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"ഒന്നുമില്ല"</string>
<string name="add" msgid="2894574044585549298">"ചേർക്കുക"</string>
<string name="deselect" msgid="4297825044827769490">"തിരഞ്ഞെടുത്തത് മാറ്റുക"</string>
<string name="deselected" msgid="8488133193326208475">"തിരഞ്ഞെടുത്തത് മാറ്റി"</string>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index bc12221..1a53343 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Зөвшөөрөх"</string>
<string name="deny" msgid="6040983710442068936">"Татгалзах"</string>
<string name="picker_browse" msgid="5554477454636075934">"Үзэх…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Тохиргоо"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Үүлэн медиа апп"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Android Photopicker-д өөр үйлчилгээнээс хуулбарласан зураг болон видеог хуваалцаарай"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Дараахаас үүлэн медиад хандах"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Байхгүй"</string>
<string name="add" msgid="2894574044585549298">"Нэмэх"</string>
<string name="deselect" msgid="4297825044827769490">"Сонголтыг цуцлах"</string>
<string name="deselected" msgid="8488133193326208475">"Сонголтыг цуцалсан"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index a4f7479..69ff378 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"अनुमती द्या"</string>
<string name="deny" msgid="6040983710442068936">"नकार द्या"</string>
<string name="picker_browse" msgid="5554477454636075934">"ब्राउझ करा…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"सेटिंग्ज"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"क्लाउड मीडिया अॅप"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"तुम्ही इतर सेवांवरून Android फोटोपिकरवर बॅक अप घेतलेले फोटो आणि व्हिडिओ शेअर करा"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"येथून क्लाउड मीडिया अॅक्सेस करा"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"काहीही नाही"</string>
<string name="add" msgid="2894574044585549298">"जोडा"</string>
<string name="deselect" msgid="4297825044827769490">"निवड रद्द करा"</string>
<string name="deselected" msgid="8488133193326208475">"निवड रद्द केली आहे"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 0aae838..a4dbd7f 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Benarkan"</string>
<string name="deny" msgid="6040983710442068936">"Tolak"</string>
<string name="picker_browse" msgid="5554477454636075934">"Semak imbas…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Tetapan"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Apl media awan"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Kongsi foto dan video yang anda sandarkan daripada perkhidmatan lain dalam Pemilih Foto Android"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Akses media awan daripada"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Tiada"</string>
<string name="add" msgid="2894574044585549298">"Tambah"</string>
<string name="deselect" msgid="4297825044827769490">"Nyahpilih"</string>
<string name="deselected" msgid="8488133193326208475">"Dinyahpilih"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index 2ad6fbe..01a3459 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"ခွင့်ပြုရန်"</string>
<string name="deny" msgid="6040983710442068936">"ပယ်ရန်"</string>
<string name="picker_browse" msgid="5554477454636075934">"ဖွင့်ကြည့်ရန်…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"ဆက်တင်များ"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Cloud မီဒီယာအက်ပ်"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Android Photopicker အတွင်း အခြားဝန်ဆောင်မှုများမှ အရန်သိမ်းသော ဓာတ်ပုံနှင့် ဗီဒီယိုများ မျှဝေနိုင်သည်"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Cloud မီဒီယာကို ဤနေရာမှ ဝင်သုံးရန်"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"မရှိ"</string>
<string name="add" msgid="2894574044585549298">"ထည့်ရန်"</string>
<string name="deselect" msgid="4297825044827769490">"မရွေးပါနှင့်"</string>
<string name="deselected" msgid="8488133193326208475">"ရွေးချယ်မထားပါ"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 1a11fbe..5948714 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Tillat"</string>
<string name="deny" msgid="6040983710442068936">"Avvis"</string>
<string name="picker_browse" msgid="5554477454636075934">"Bla gjennom…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Innstillinger"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Skymedieapp"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Del bilder og videoer du sikkerhetskopierer fra andre tjenester, i Android Photopicker"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Åpne skymedier fra"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Ingen"</string>
<string name="add" msgid="2894574044585549298">"Legg til"</string>
<string name="deselect" msgid="4297825044827769490">"Fjern merking"</string>
<string name="deselected" msgid="8488133193326208475">"Ikke valgt"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index e192e65..6502e4f 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"अनुमति दिनुहोस्"</string>
<string name="deny" msgid="6040983710442068936">"अस्वीकार गर्नुहोस्"</string>
<string name="picker_browse" msgid="5554477454636075934">"ब्राउज गर्नुहोस्…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"सेटिङ"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"क्लाउड मिडिया एप"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"आफूले Android Photopicker मा विभिन्न सेवाहरूबाट ब्याकअप गर्ने फोटो तथा भिडियोहरू सेयर गर्नुहोस्"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"यसबाट क्लाउड मिडिया प्रयोग गर्नुहोस्"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"कुनै पनि होइन"</string>
<string name="add" msgid="2894574044585549298">"हाल्नुहोस्"</string>
<string name="deselect" msgid="4297825044827769490">"चयन रद्द गर्नुहोस्"</string>
<string name="deselected" msgid="8488133193326208475">"चयन रद्द गरियो"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index a6dfe0d..0a6b4a5 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Toestaan"</string>
<string name="deny" msgid="6040983710442068936">"Weigeren"</string>
<string name="picker_browse" msgid="5554477454636075934">"Browsen…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Instellingen"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Cloudmedia-app"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Deel foto\'s en video\'s waarvan je een back-up hebt gemaakt uit andere services in de fotokiezer van Android"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Cloudmedia openen vanuit"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Geen"</string>
<string name="add" msgid="2894574044585549298">"Toevoegen"</string>
<string name="deselect" msgid="4297825044827769490">"Deselecteren"</string>
<string name="deselected" msgid="8488133193326208475">"Gedeselecteerd"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 3d8cd34..74ea138 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="deny" msgid="6040983710442068936">"ଅଗ୍ରାହ୍ୟ କରନ୍ତୁ"</string>
<string name="picker_browse" msgid="5554477454636075934">"ବ୍ରାଉଜ କରନ୍ତୁ…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"ସେଟିଂସ"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"କ୍ଲାଉଡ ମିଡିଆ ଆପ"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Android Photopickerରେ ଅନ୍ୟ ସେବାଗୁଡ଼ିକରୁ ଆପଣ ବେକଅପ ନେଇଥିବା ଫଟୋ ଓ ଭିଡିଓଗୁଡ଼ିକୁ ସେୟାର କରନ୍ତୁ"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"ଏଠାରୁ କ୍ଲାଉଡ ମିଡିଆକୁ ଆକ୍ସେସ କରନ୍ତୁ"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"କିଛି ନାହିଁ"</string>
<string name="add" msgid="2894574044585549298">"ଯୋଗ କରନ୍ତୁ"</string>
<string name="deselect" msgid="4297825044827769490">"ଅଚୟନ କରନ୍ତୁ"</string>
<string name="deselected" msgid="8488133193326208475">"ଅଚୟନ କରାଯାଇଛି"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 6972156..b43a7a9 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"ਆਗਿਆ ਦਿਓ"</string>
<string name="deny" msgid="6040983710442068936">"ਨਾ ਕਰਨ ਦਿਓ"</string>
<string name="picker_browse" msgid="5554477454636075934">"ਬ੍ਰਾਊਜ਼ ਕਰੋ…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"ਸੈਟਿੰਗਾਂ"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"ਕਲਾਊਡ ਮੀਡੀਆ ਐਪ"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Android ਦੇ ਫ਼ੋਟੋ ਚੋਣਕਾਰ ਦੀ ਮਦਦ ਨਾਲ ਉਨ੍ਹਾਂ ਫ਼ੋਟੋਆਂ ਅਤੇ ਵੀਡੀਓ ਨੂੰ ਸਾਂਝਾ ਕਰੋ ਜਿਨ੍ਹਾਂ ਦਾ ਬੈਕਅੱਪ ਤੁਸੀਂ ਹੋਰ ਸੇਵਾਵਾਂ ਤੋਂ ਲਿਆ ਹੈ"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"ਇੱਥੋਂ ਕਲਾਊਡ ਮੀਡੀਆ ਤੱਕ ਪਹੁੰਚ ਕਰੋ"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"ਕੋਈ ਨਹੀਂ"</string>
<string name="add" msgid="2894574044585549298">"ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="deselect" msgid="4297825044827769490">"ਅਣ-ਚੁਣਿਆ ਕਰੋ"</string>
<string name="deselected" msgid="8488133193326208475">"ਅਣ-ਚੁਣਿਆ"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 521ac08..b871747 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Zezwól"</string>
<string name="deny" msgid="6040983710442068936">"Odmów"</string>
<string name="picker_browse" msgid="5554477454636075934">"Przeglądaj…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Ustawienia"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Aplikacja do multimediów w chmurze"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Udostępniaj zdjęcia i filmy, których kopie zapasowe tworzysz w innych usługach, w Selektorze zdjęć na Androidzie"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Otwieraj multimedia w chmurze za pomocą:"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Brak"</string>
<string name="add" msgid="2894574044585549298">"Dodaj"</string>
<string name="deselect" msgid="4297825044827769490">"Odznacz"</string>
<string name="deselected" msgid="8488133193326208475">"Usunięto wybór"</string>
diff --git a/res/values-pt-rBR/strings.xml b/res/values-pt-rBR/strings.xml
index 32a46da..cba5cb3 100644
--- a/res/values-pt-rBR/strings.xml
+++ b/res/values-pt-rBR/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Permitir"</string>
<string name="deny" msgid="6040983710442068936">"Negar"</string>
<string name="picker_browse" msgid="5554477454636075934">"Procurar…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Configurações"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"App de mídia em nuvem"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Compartilhar fotos e vídeos que você armazena em backup de outros serviços no Seletor de fotos do Android"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Acessar a mídia em nuvem de"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Nenhum"</string>
<string name="add" msgid="2894574044585549298">"Adicionar"</string>
<string name="deselect" msgid="4297825044827769490">"Desmarcar"</string>
<string name="deselected" msgid="8488133193326208475">"Desmarcada"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index f33d7eb..1bf6aa6 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Permitir"</string>
<string name="deny" msgid="6040983710442068936">"Recusar"</string>
<string name="picker_browse" msgid="5554477454636075934">"Procurar…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Definições"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"App de multimédia na nuvem"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Partilhe fotos e vídeos dos quais fez uma cópia de segurança a partir de outros serviços no Android Photopicker"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Aceda a multimédia na nuvem a partir de"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Nenhuma"</string>
<string name="add" msgid="2894574044585549298">"Adicionar"</string>
<string name="deselect" msgid="4297825044827769490">"Desselecionar"</string>
<string name="deselected" msgid="8488133193326208475">"Desmarcado"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 32a46da..cba5cb3 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Permitir"</string>
<string name="deny" msgid="6040983710442068936">"Negar"</string>
<string name="picker_browse" msgid="5554477454636075934">"Procurar…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Configurações"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"App de mídia em nuvem"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Compartilhar fotos e vídeos que você armazena em backup de outros serviços no Seletor de fotos do Android"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Acessar a mídia em nuvem de"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Nenhum"</string>
<string name="add" msgid="2894574044585549298">"Adicionar"</string>
<string name="deselect" msgid="4297825044827769490">"Desmarcar"</string>
<string name="deselected" msgid="8488133193326208475">"Desmarcada"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 8fa0ce2..96ddff1 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Permite"</string>
<string name="deny" msgid="6040983710442068936">"Refuz"</string>
<string name="picker_browse" msgid="5554477454636075934">"Răsfoiește…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Setări"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Aplicația media în cloud"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Distribuie fotografiile și videoclipurile cărora le faci backup din alte servicii în Android Photopicker"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Accesează conținutul media în cloud din"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Niciuna"</string>
<string name="add" msgid="2894574044585549298">"Adaugă"</string>
<string name="deselect" msgid="4297825044827769490">"Debifează"</string>
<string name="deselected" msgid="8488133193326208475">"Deselectat"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index f00ee4e..3475aac 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Разрешить"</string>
<string name="deny" msgid="6040983710442068936">"Запретить"</string>
<string name="picker_browse" msgid="5554477454636075934">"Посмотреть"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Настройки"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Приложение для мультимедиа в облаке"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Делитесь фотографиями и видео из других сервисов, для которых вы сохранили резервные копии, в окне выбора фотографий Android"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Получите доступ к мультимедиа в облаке"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Нет"</string>
<string name="add" msgid="2894574044585549298">"Добавить"</string>
<string name="deselect" msgid="4297825044827769490">"Отменить выбор"</string>
<string name="deselected" msgid="8488133193326208475">"Выбор отменен"</string>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index f2ab04c..b328fba 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"ඉඩ දෙන්න"</string>
<string name="deny" msgid="6040983710442068936">"ප්රතික්ෂේප කරන්න"</string>
<string name="picker_browse" msgid="5554477454636075934">"බ්රවුස් කරන්න…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"සැකසීම්"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"ක්ලවුඩ් මාධ්ය යෙදුම"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"ඔබ Android ඡායාරූප තෝරකය තුළ වෙනත් සේවාවලින් උපස්ථ කරන ඡායාරූප සහ වීඩියෝ බෙදා ගන්න"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"මෙයින් ක්ලවුඩ් මාධ්ය වෙත ප්රවේශ වන්න"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"කිසිවක් නැත"</string>
<string name="add" msgid="2894574044585549298">"එක් කරන්න"</string>
<string name="deselect" msgid="4297825044827769490">"නොතෝරන්න"</string>
<string name="deselected" msgid="8488133193326208475">"නොතෝරන ලද"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 93d3d1b..be30b85 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Povoliť"</string>
<string name="deny" msgid="6040983710442068936">"Zamietnuť"</string>
<string name="picker_browse" msgid="5554477454636075934">"Prehliadať…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Nastavenia"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Aplikácia na prístup k médiám v cloude"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Zdieľanie fotiek a videí, ktoré zálohujete z iných služieb v nástroji Android Photopicker"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Získavať prístup k médiám v cloude v aplikácii"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Žiadne"</string>
<string name="add" msgid="2894574044585549298">"Pridať"</string>
<string name="deselect" msgid="4297825044827769490">"Zrušiť výber"</string>
<string name="deselected" msgid="8488133193326208475">"Výber bol zrušený"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 4c12cf4..229341d 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Dovoli"</string>
<string name="deny" msgid="6040983710442068936">"Zavrni"</string>
<string name="picker_browse" msgid="5554477454636075934">"Brskanje …"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Nastavitve"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Aplikacija za predstavnost v oblaku"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Delite fotografije in videoposnetke, ki jih varnostno kopirate v drugih storitvah, z Androidovim izbirnikom fotografij."</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Dostop do predstavnosti v oblaku v storitvi"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Brez"</string>
<string name="add" msgid="2894574044585549298">"Dodaj"</string>
<string name="deselect" msgid="4297825044827769490">"Počisti izbiro"</string>
<string name="deselected" msgid="8488133193326208475">"Izbor je preklican"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index dc2358a..9307a21 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Lejo"</string>
<string name="deny" msgid="6040983710442068936">"Refuzo"</string>
<string name="picker_browse" msgid="5554477454636075934">"Shfleto…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Cilësimet"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Aplikacioni i medias në renë kompjuterike"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Ndaj fotografitë dhe videot që rezervon nga shërbimet e tjera në Android Photopicker"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Qasu te media në renë kompjuterike nga"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Asnjë"</string>
<string name="add" msgid="2894574044585549298">"Shto"</string>
<string name="deselect" msgid="4297825044827769490">"Hiq përzgjedhjen"</string>
<string name="deselected" msgid="8488133193326208475">"Zgjedhja është hequr"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 5db0e87..b65e143 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Дозволи"</string>
<string name="deny" msgid="6040983710442068936">"Одбиј"</string>
<string name="picker_browse" msgid="5554477454636075934">"Прегледај…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Подешавања"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Апликација за медије у клауду"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Делите слике и видео снимке за које правите резервне копије из других услуга у Android бирачу слика"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Приступајте медијима у клауду из"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Ништа"</string>
<string name="add" msgid="2894574044585549298">"Додај"</string>
<string name="deselect" msgid="4297825044827769490">"Опозови избор"</string>
<string name="deselected" msgid="8488133193326208475">"Опозван је избор"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 8c66d05..0496ea0 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Tillåt"</string>
<string name="deny" msgid="6040983710442068936">"Neka"</string>
<string name="picker_browse" msgid="5554477454636075934">"Bläddra bland …"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Inställningar"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Molnmedieapp"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Dela foton och videor du säkerhetskopierar från andra tjänster med Androids fotoväljare"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Få tillgång till media i molnet från"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Inga"</string>
<string name="add" msgid="2894574044585549298">"Lägg till"</string>
<string name="deselect" msgid="4297825044827769490">"Avmarkera"</string>
<string name="deselected" msgid="8488133193326208475">"Avmarkerad"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 2379c1c..1467627 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Ruhusu"</string>
<string name="deny" msgid="6040983710442068936">"Kataa"</string>
<string name="picker_browse" msgid="5554477454636075934">"Vinjari…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Mipangilio"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Programu ya maudhui ya kwenye wingu"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Shiriki nakala za picha na video unazohifadhi kutoka katika huduma nyinginezo kwenye Kiteua picha cha Android"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Fikia maudhui ya kwenye wingu katika"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Hamna"</string>
<string name="add" msgid="2894574044585549298">"Weka"</string>
<string name="deselect" msgid="4297825044827769490">"Acha kuchagua"</string>
<string name="deselected" msgid="8488133193326208475">"Umeacha kuchagua"</string>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 6add1d7..9ef49c3 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"அனுமதி"</string>
<string name="deny" msgid="6040983710442068936">"நிராகரி"</string>
<string name="picker_browse" msgid="5554477454636075934">"உலாவுக…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"அமைப்புகள்"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"கிளவுடு மீடியா ஆப்ஸ்"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"பிற சேவைகளில் இருந்து காப்புப் பிரதி எடுக்கும் படங்களையும் வீடியோக்களையும் Android ஃபோட்டோ தேர்வுக் கருவி மூலம் பகிரலாம்"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"கிளவுட் மீடியாவை இதிலிருந்து அணுகும்"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"எதுவுமில்லை"</string>
<string name="add" msgid="2894574044585549298">"சேர்"</string>
<string name="deselect" msgid="4297825044827769490">"தேர்வுநீக்கு"</string>
<string name="deselected" msgid="8488133193326208475">"தேர்வுநீக்கப்பட்டது"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 7e360e3..9db3502 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"అనుమతించండి"</string>
<string name="deny" msgid="6040983710442068936">"నిరాకరించండి"</string>
<string name="picker_browse" msgid="5554477454636075934">"బ్రౌజ్ చేయండి…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"సెట్టింగ్లు"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"క్లౌడ్ మీడియా యాప్"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Android ఫోటోపికర్లోని ఇతర సర్వీస్ల నుండి మీరు బ్యాకప్ చేసే ఫోటోలు, వీడియోలను షేర్ చేయండి"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"దాని నుండి క్లౌడ్ మీడియాను యాక్సెస్ చేయండి"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"ఏవీ లేవు"</string>
<string name="add" msgid="2894574044585549298">"జోడించు"</string>
<string name="deselect" msgid="4297825044827769490">"ఎంపికను తొలగించండి"</string>
<string name="deselected" msgid="8488133193326208475">"ఎంపికను తొలగించండి"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 0d6a350..e9cbb77 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"อนุญาต"</string>
<string name="deny" msgid="6040983710442068936">"ปฏิเสธ"</string>
<string name="picker_browse" msgid="5554477454636075934">"เรียกดู…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"การตั้งค่า"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"แอปสื่อในระบบคลาวด์"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"แชร์รูปภาพและวิดีโอที่คุณสำรองข้อมูลไว้จากบริการอื่นๆ ใน Android Photopicker"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"เข้าถึงสื่อในระบบคลาวด์จาก"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"ไม่มี"</string>
<string name="add" msgid="2894574044585549298">"เพิ่ม"</string>
<string name="deselect" msgid="4297825044827769490">"ยกเลิกการเลือก"</string>
<string name="deselected" msgid="8488133193326208475">"ยกเลิกการเลือก"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index f7962a8..1f12afc 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Payagan"</string>
<string name="deny" msgid="6040983710442068936">"Tanggihan"</string>
<string name="picker_browse" msgid="5554477454636075934">"Mag-browse…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Mga Setting"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Cloud media app"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Magbahagi ng mga larawan at video na na-back up mo mula sa iba pang serbisyo sa Android Photopicker"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"I-access ang cloud media sa"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Wala"</string>
<string name="add" msgid="2894574044585549298">"Magdagdag"</string>
<string name="deselect" msgid="4297825044827769490">"I-deselect"</string>
<string name="deselected" msgid="8488133193326208475">"Na-deselect"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 4f66ae4..c287188 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"İzin ver"</string>
<string name="deny" msgid="6040983710442068936">"Reddet"</string>
<string name="picker_browse" msgid="5554477454636075934">"Göz at…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Ayarlar"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Bulut medya uygulaması"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Diğer hizmetlerden yedeklediğiniz fotoğrafları ve videoları Android fotoğraf seçicide paylaşın"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Şuradaki bulut medyasına erişin"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Yok"</string>
<string name="add" msgid="2894574044585549298">"Ekle"</string>
<string name="deselect" msgid="4297825044827769490">"Seçimi kaldır"</string>
<string name="deselected" msgid="8488133193326208475">"Seçimi kaldırıldı"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 5c06571..af77f0a 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Дозволити"</string>
<string name="deny" msgid="6040983710442068936">"Заборонити"</string>
<string name="picker_browse" msgid="5554477454636075934">"Перегляд…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Налаштування"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Хмарний мультимедійний додаток"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Діліться знімками й відео, які ви автоматично завантажуєте з інших сервісів, за допомогою засобу вибору фотографій Android"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Постачальник медіаконтенту з хмари"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Немає"</string>
<string name="add" msgid="2894574044585549298">"Додати"</string>
<string name="deselect" msgid="4297825044827769490">"Не вибирати"</string>
<string name="deselected" msgid="8488133193326208475">"Не вибрано"</string>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 9fec975..67111ba 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"اجازت دیں"</string>
<string name="deny" msgid="6040983710442068936">"مسترد کریں"</string>
<string name="picker_browse" msgid="5554477454636075934">"براؤز کریں…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"ترتیبات"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"کلاؤڈ میڈیا ایپ"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"ان تصاویر اور ویڈیوز کا اشتراک کریں جنہیں آپ Android Photopicker میں دیگر سروسز سے بیک اپ کرتے ہیں"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"اس سے کلاؤڈ میڈیا تک رسائی حاصل کریں"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"کوئی نہیں"</string>
<string name="add" msgid="2894574044585549298">"شامل کریں"</string>
<string name="deselect" msgid="4297825044827769490">"غیر منتخب کریں"</string>
<string name="deselected" msgid="8488133193326208475">"غیر منتخب کردہ"</string>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index b9b9b16..b9c913f 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Ruxsat"</string>
<string name="deny" msgid="6040983710442068936">"Rad etish"</string>
<string name="picker_browse" msgid="5554477454636075934">"Tanlash…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Sozlamalar"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Bulutli media ilovasi"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Android Suratni tanlash vositasi orqali boshqa xizmatlarda zaxiralangan rasm va videolarni ulashing"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Bulutli media kontentni ochish"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Hech qanday"</string>
<string name="add" msgid="2894574044585549298">"Kiritish"</string>
<string name="deselect" msgid="4297825044827769490">"Tanlovni bekor qilish"</string>
<string name="deselected" msgid="8488133193326208475">"Tanlovi yechilgan"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 3d20a1c..6f739eb 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Cho phép"</string>
<string name="deny" msgid="6040983710442068936">"Từ chối"</string>
<string name="picker_browse" msgid="5554477454636075934">"Duyệt qua…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Cài đặt"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"Ứng dụng nội dung phương tiện trên đám mây"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Chia sẻ ảnh và video bạn sao lưu qua các dịch vụ khác trong Android Photopicker"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Truy cập nội dung phương tiện trên đám mây qua"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Không có"</string>
<string name="add" msgid="2894574044585549298">"Thêm"</string>
<string name="deselect" msgid="4297825044827769490">"Bỏ chọn"</string>
<string name="deselected" msgid="8488133193326208475">"Đã bỏ chọn"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 257dd97..fe36aea 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"允许"</string>
<string name="deny" msgid="6040983710442068936">"拒绝"</string>
<string name="picker_browse" msgid="5554477454636075934">"浏览…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"设置"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"云端媒体应用"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"在 Android 照片选择器中分享您从其他服务备份的照片和视频"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"从以下位置访问云端媒体:"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"无"</string>
<string name="add" msgid="2894574044585549298">"添加"</string>
<string name="deselect" msgid="4297825044827769490">"取消选择"</string>
<string name="deselected" msgid="8488133193326208475">"已取消选中"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index f7c3a91..ae26730 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"允許"</string>
<string name="deny" msgid="6040983710442068936">"拒絕"</string>
<string name="picker_browse" msgid="5554477454636075934">"瀏覽…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"設定"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"雲端媒體應用程式"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"在 Android 相片點選器分享從其他服務備份的相片和影片"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"從以下位置存取雲端媒體:"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"無"</string>
<string name="add" msgid="2894574044585549298">"新增"</string>
<string name="deselect" msgid="4297825044827769490">"取消選取"</string>
<string name="deselected" msgid="8488133193326208475">"已取消選取"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 3458ad2..3875a1d 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"允許"</string>
<string name="deny" msgid="6040983710442068936">"拒絕"</string>
<string name="picker_browse" msgid="5554477454636075934">"瀏覽…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"設定"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"雲端媒體應用程式"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"在 Android 相片挑選工具中分享你從其他服務備份而來的相片和影片"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"從以下位置存取雲端媒體:"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"無"</string>
<string name="add" msgid="2894574044585549298">"新增"</string>
<string name="deselect" msgid="4297825044827769490">"取消選取"</string>
<string name="deselected" msgid="8488133193326208475">"已取消選取"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index bef410b..cb3c802 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -39,16 +39,11 @@
<string name="allow" msgid="8885707816848569619">"Vumela"</string>
<string name="deny" msgid="6040983710442068936">"Nqaba"</string>
<string name="picker_browse" msgid="5554477454636075934">"Bhrawuza…"</string>
- <!-- no translation found for picker_settings (7388913035769329672) -->
- <skip />
- <!-- no translation found for picker_settings_title (5647700706470673258) -->
- <skip />
- <!-- no translation found for picker_settings_description (7486394662725656081) -->
- <skip />
- <!-- no translation found for picker_settings_selection_message (245453573086488596) -->
- <skip />
- <!-- no translation found for picker_settings_no_provider (2582311853680058223) -->
- <skip />
+ <string name="picker_settings" msgid="7388913035769329672">"Amasethingi"</string>
+ <string name="picker_settings_title" msgid="5647700706470673258">"I-app yemidiya ye-cloud"</string>
+ <string name="picker_settings_description" msgid="7486394662725656081">"Yabelana ngezithombe namavidiyo owenza ikhophi yasenqolobaneni esuka kwezinye izinsiza ku-Android Photopicker"</string>
+ <string name="picker_settings_selection_message" msgid="245453573086488596">"Finyelela imidiya yacloud ukusuka"</string>
+ <string name="picker_settings_no_provider" msgid="2582311853680058223">"Lutho"</string>
<string name="add" msgid="2894574044585549298">"Engeza"</string>
<string name="deselect" msgid="4297825044827769490">"Susa ukukhetha"</string>
<string name="deselected" msgid="8488133193326208475">"Okususwe ekukhethweni"</string>
diff --git a/src/com/android/providers/media/ConfigStore.java b/src/com/android/providers/media/ConfigStore.java
index b5a4866..641f56d 100644
--- a/src/com/android/providers/media/ConfigStore.java
+++ b/src/com/android/providers/media/ConfigStore.java
@@ -19,9 +19,11 @@
import static android.provider.DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT;
import android.os.Binder;
+import android.os.SystemProperties;
import android.provider.DeviceConfig;
import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
import androidx.core.util.Supplier;
import com.android.modules.utils.build.SdkLevel;
@@ -114,7 +116,9 @@
*/
class ConfigStoreImpl implements ConfigStore {
private static final String KEY_TAKE_OVER_GET_CONTENT = "take_over_get_content";
- private static final String KEY_STABILISE_VOLUME_INTERNAL = "stablise_volume_internal";
+
+ @VisibleForTesting
+ public static final String KEY_STABILISE_VOLUME_INTERNAL = "stablise_volume_internal";
private static final String KEY_TRANSCODE_ENABLED = "transcode_enabled";
private static final String KEY_TRANSCODE_OPT_OUT_STRATEGY_ENABLED = "transcode_default";
@@ -122,6 +126,10 @@
private static final String KEY_TRANSCODE_COMPAT_MANIFEST = "transcode_compat_manifest";
private static final String KEY_TRANSCODE_COMPAT_STALE = "transcode_compat_stale";
+ private static final String SYSPROP_TRANSCODE_MAX_DURATION =
+ "persist.sys.fuse.transcode_max_file_duration_ms";
+ private static final int TRANSCODE_MAX_DURATION_INVALID = 0;
+
private static final String KEY_PICKER_ALLOWED_CLOUD_PROVIDERS = "allowed_cloud_providers";
private static final String KEY_PICKER_SYNC_DELAY = "default_sync_delay_ms";
@@ -163,6 +171,19 @@
@Override
public int getTranscodeMaxDurationMs() {
+ // First check if OEMs overwrite default duration via system property.
+ int maxDurationMs = SystemProperties.getInt(
+ SYSPROP_TRANSCODE_MAX_DURATION, TRANSCODE_MAX_DURATION_INVALID);
+
+ // Give priority to OEM value if set. Only accept larger values, which can be desired
+ // for more performant devices. Lower values may result in unexpected behaviour
+ // (a value of 0 would mean transcoding is actually disabled) or break CTS tests (a
+ // value small enough to prevent transcoding the videos under test).
+ // Otherwise, fallback to device config / default values.
+ if (maxDurationMs != TRANSCODE_MAX_DURATION_INVALID
+ && maxDurationMs > DEFAULT_TRANSCODE_MAX_DURATION) {
+ return maxDurationMs;
+ }
return getIntDeviceConfig(KEY_TRANSCODE_MAX_DURATION, DEFAULT_TRANSCODE_MAX_DURATION);
}
diff --git a/src/com/android/providers/media/DatabaseHelper.java b/src/com/android/providers/media/DatabaseHelper.java
index f28cb70..55974f5 100644
--- a/src/com/android/providers/media/DatabaseHelper.java
+++ b/src/com/android/providers/media/DatabaseHelper.java
@@ -154,7 +154,7 @@
*/
private static final String DATA_MEDIA_XATTR_DIRECTORY_PATH = "/data/media/0";
- private static final int LEVEL_DB_READ_LIMIT = 1000;
+ protected static final int LEVEL_DB_READ_LIMIT = 1000;
static final String INTERNAL_DATABASE_NAME = "internal.db";
static final String EXTERNAL_DATABASE_NAME = "external.db";
@@ -552,23 +552,36 @@
getExternalStorageDbXattrPath(), getSessionIdXattrKeyForDatabase());
if (!lastUsedSessionIdFromExternalStoragePathXattr.isPresent()) {
// First time scenario will have no session id at /data/media/0.
+ // Trigger database backup to external storage because
+ // StableUrisIdleMaintenanceService will be attempted to run only once in 7days.
+ // Any rollback before that will not recover DB rows.
+ BackgroundThread.getExecutor().execute(
+ () -> mediaProvider.backupInternalDatabase(null));
+ // Set next row id in External Storage to handle rollback in future.
+ backupNextRowId(NEXT_ROW_ID_DEFAULT_BILLION_VALUE);
updateSessionIdInDatabaseAndExternalStorage(db);
return;
}
+ Optional<Long> nextRowIdFromXattrOptional = getNextRowIdFromXattr();
// Check if session is same as last used.
- if (isLastUsedDatabaseSession(db)) {
+ if (isLastUsedDatabaseSession(db) && nextRowIdFromXattrOptional.isPresent()) {
// Same session id present as xattr on DB and External Storage
+ Log.i(TAG, String.format(Locale.ROOT,
+ "No database change across sequential open calls for %s.", mName));
+ mNextRowIdBackup.set(nextRowIdFromXattrOptional.get());
updateSessionIdInDatabaseAndExternalStorage(db);
return;
}
+ Log.w(TAG, String.format(Locale.ROOT, "%s database inconsistency identified.", mName));
// Delete old data and create new schema.
recreateLatestSchema(db);
// Recover data from backup
// Ensure we do not back up in case of recovery.
mIsRecovering.set(true);
recoverData(mediaProvider, db, volumeName);
+ updateNextRowIdInDatabaseAndExternalStorage(db);
mIsRecovering.set(false);
updateSessionIdInDatabaseAndExternalStorage(db);
Log.d(TAG, "Recovery completed for " + mName);
@@ -659,6 +672,11 @@
}
private void tryRecoverRowIdSequence(SQLiteDatabase db) {
+ if (isInternal()) {
+ // Database row id recovery for internal is handled in tryRecoverDatabase()
+ return;
+ }
+
if (!isNextRowIdBackupEnabled()) {
Log.d(TAG, "Skipping row id recovery as backup is not enabled.");
return;
@@ -2436,8 +2454,8 @@
Os.getxattr(DATA_MEDIA_XATTR_DIRECTORY_PATH,
getNextRowIdXattrKeyForDatabase()))));
} catch (Exception e) {
- Log.e(TAG, String.format(Locale.ROOT, "Xattr:%s not found on external storage.",
- getNextRowIdXattrKeyForDatabase()), e);
+ Log.e(TAG, String.format(Locale.ROOT, "Xattr:%s not found on external storage: %s",
+ getNextRowIdXattrKeyForDatabase(), e));
return Optional.empty();
}
}
@@ -2509,13 +2527,6 @@
return false;
}
- if (isInternal()) {
- // Skip id reuse fix for internal db as it can lead to ids starting from a billion
- // and can cause aberrant behaviour in Ringtones Manager. Reference: b/229153534.
- Log.v(TAG, "Skipping next row id backup for internal database.");
- return false;
- }
-
if (!(new File(DATA_MEDIA_XATTR_DIRECTORY_PATH)).exists()) {
Log.w(TAG, String.format(Locale.ROOT,
"Skipping row id recovery as path:%s does not exist.",
diff --git a/src/com/android/providers/media/MediaProvider.java b/src/com/android/providers/media/MediaProvider.java
index 816f27a..3dd35ca 100644
--- a/src/com/android/providers/media/MediaProvider.java
+++ b/src/com/android/providers/media/MediaProvider.java
@@ -44,11 +44,13 @@
import static android.provider.MediaStore.QUERY_ARG_MATCH_TRASHED;
import static android.provider.MediaStore.QUERY_ARG_REDACTED_URI;
import static android.provider.MediaStore.QUERY_ARG_RELATED_URI;
+import static android.provider.MediaStore.READ_BACKED_UP_FILE_PATHS;
import static android.provider.MediaStore.getVolumeName;
import static android.system.OsConstants.F_GETFL;
import static com.android.providers.media.DatabaseHelper.EXTERNAL_DATABASE_NAME;
import static com.android.providers.media.DatabaseHelper.INTERNAL_DATABASE_NAME;
+import static com.android.providers.media.DatabaseHelper.LEVEL_DB_READ_LIMIT;
import static com.android.providers.media.LocalCallingIdentity.APPOP_REQUEST_INSTALL_PACKAGES_FOR_SHARED_UID;
import static com.android.providers.media.LocalCallingIdentity.PERMISSION_ACCESS_MTP;
import static com.android.providers.media.LocalCallingIdentity.PERMISSION_INSTALL_PACKAGES;
@@ -106,6 +108,7 @@
import static com.android.providers.media.util.SyntheticPathUtils.isRedactedPath;
import static com.android.providers.media.util.SyntheticPathUtils.isSyntheticPath;
+import android.Manifest;
import android.annotation.IntDef;
import android.app.AppOpsManager;
import android.app.AppOpsManager.OnOpActiveChangedListener;
@@ -792,6 +795,9 @@
acceptWithExpansion(helper::notifyUpdate, oldRow.getVolumeName(), oldRow.getId(),
oldRow.getMediaType(), isDownload);
updateNextRowIdXattr(helper, newRow.getId());
+ if (backedUpValuesChanged(helper, oldRow, newRow)) {
+ markBackupAsDirty(helper, oldRow);
+ }
helper.postBackground(() -> {
if (helper.isExternal()) {
// Update the quota type on the filesystem
@@ -866,6 +872,44 @@
}
};
+ private boolean backedUpValuesChanged(DatabaseHelper helper, FileRow oldRow, FileRow newRow) {
+ if (helper.isInternal()) {
+ return backedUpValuesChangedForInternal(oldRow, newRow);
+ }
+
+ return false;
+ }
+
+ private boolean backedUpValuesChangedForInternal(FileRow oldRow, FileRow newRow) {
+ if (oldRow.getId() == newRow.getId() && oldRow.isFavorite() == newRow.isFavorite()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ private void markBackupAsDirty(DatabaseHelper databaseHelper, FileRow updatedRow) {
+ if (!isStableUrisEnabled(updatedRow.getVolumeName())) {
+ return;
+ }
+
+ if (databaseHelper.isDatabaseRecovering()) {
+ return;
+ }
+
+ final String updatedFilePath = updatedRow.getPath();
+ // For all internal file paths, redirect to external primary fuse daemon.
+ final String fuseDaemonFilePath = getFuseDaemonFilePath(updatedFilePath);
+ try {
+ getFuseDaemonForPath(fuseDaemonFilePath).backupVolumeDbData(updatedFilePath,
+ BackupIdRow.serialize(BackupIdRow.newBuilder(updatedRow.getId()).setIsDirty(
+ true).build()));
+ } catch (IOException e) {
+ Log.e(TAG, "Failure in marking data as dirty to external storage for path:"
+ + updatedFilePath, e);
+ }
+ }
+
/**
* Backs up DB data in external storage to recover in case of DB rollback.
*/
@@ -880,8 +924,7 @@
}
// For all internal file paths, redirect to external primary fuse daemon.
- final String fuseDaemonFilePath = insertedFilePath.startsWith("/storage") ? insertedFilePath
- : "/storage/emulated/" + UserHandle.myUserId();
+ final String fuseDaemonFilePath = getFuseDaemonFilePath(insertedFilePath);
try {
final BackupIdRow value = createBackupIdRow(insertedRow);
getFuseDaemonForPath(fuseDaemonFilePath).backupVolumeDbData(insertedFilePath,
@@ -891,6 +934,11 @@
}
}
+ private String getFuseDaemonFilePath(String filePath) {
+ return filePath.startsWith("/storage") ? filePath
+ : "/storage/emulated/" + UserHandle.myUserId();
+ }
+
private BackupIdRow createBackupIdRow(FileRow insertedRow) {
BackupIdRow.Builder builder = BackupIdRow.newBuilder(insertedRow.getId());
builder.setIsFavorite(insertedRow.isFavorite() ? 1 : 0);
@@ -907,8 +955,7 @@
String deletedFilePath = deletedRow.getPath();
// For all internal file paths, redirect to external primary fuse daemon.
- String fuseDaemonFilePath = deletedFilePath.startsWith("/storage") ? deletedFilePath
- : "/storage/emulated/" + UserHandle.myUserId();
+ String fuseDaemonFilePath = getFuseDaemonFilePath(deletedFilePath);
try {
getFuseDaemonForPath(fuseDaemonFilePath).deleteDbBackup(deletedFilePath);
} catch (IOException e) {
@@ -937,8 +984,7 @@
return Optional.empty();
}
- final String fuseDaemonFilePath = filePath.startsWith("/storage") ? filePath
- : "/storage/emulated/" + UserHandle.myUserId();
+ final String fuseDaemonFilePath = getFuseDaemonFilePath(filePath);
try {
final String data = getFuseDaemonForPath(fuseDaemonFilePath).readBackedUpData(filePath);
return Optional.of(BackupIdRow.deserialize(data));
@@ -949,8 +995,12 @@
}
protected void updateNextRowIdXattr(DatabaseHelper helper, long id) {
+ if (helper.isInternal()) {
+ updateNextRowIdForInternal(helper, id);
+ return;
+ }
+
if (!helper.isNextRowIdBackupEnabled()) {
- Log.v(TAG, "Skipping next row id backup.");
return;
}
@@ -963,9 +1013,20 @@
if (id >= nextRowIdBackupOptional.get()) {
helper.backupNextRowId(id);
- } else {
- Log.v(TAG, String.format(Locale.ROOT, "Inserted id:%d less than next row id backup:%d.",
- id, nextRowIdBackupOptional.get()));
+ }
+ }
+
+ private void updateNextRowIdForInternal(DatabaseHelper helper, long id) {
+ if (!isStableUrisEnabled(MediaStore.VOLUME_INTERNAL)) {
+ return;
+ }
+ Optional<Long> nextRowIdBackupOptional = helper.getNextRowId();
+ if (!nextRowIdBackupOptional.isPresent()) {
+ return;
+ }
+
+ if (id >= nextRowIdBackupOptional.get()) {
+ helper.backupNextRowId(id);
}
}
@@ -1282,16 +1343,16 @@
mExternalStorageAuthorityAppId = UserHandle.getAppId(provider.applicationInfo.uid);
}
- checkConfigAndUpdateGetContentAlias();
+ storageNativeBootPropertyChangeListener();
mConfigStore.addOnChangeListener(
- BackgroundThread.getExecutor(), this::checkConfigAndUpdateGetContentAlias);
+ BackgroundThread.getExecutor(), this::storageNativeBootPropertyChangeListener);
PulledMetrics.initialize(context);
return true;
}
@VisibleForTesting
- protected void checkConfigAndUpdateGetContentAlias() {
+ protected void storageNativeBootPropertyChangeListener() {
final String photoPickerGetContentActivity =
PhotoPickerActivity.class.getPackage().getName() + ".PhotoPickerGetContentActivity";
final ComponentName componentName = new ComponentName(getContext().getPackageName(),
@@ -1305,6 +1366,15 @@
+ " for PhotoPickerGetContentActivity. ");
getContext().getPackageManager().setComponentEnabledSetting(componentName, expectedState,
PackageManager.DONT_KILL_APP);
+
+ if (mConfigStore.isStableUrisForInternalVolumeEnabled()
+ && mVolumeCache.getExternalVolumeNames().contains(
+ MediaStore.VOLUME_EXTERNAL_PRIMARY)) {
+ Log.i(TAG,
+ "On device config change, found stable uri support enabled. Attempting backup"
+ + " and recovery setup.");
+ setupVolumeDbBackupForInternalIfMissing();
+ }
}
Optional<DatabaseHelper> getDatabaseHelper(String dbName) {
@@ -1421,6 +1491,55 @@
}
/**
+ * Backs up databases to external storage to ensure stable URIs.
+ */
+ public void backupDatabases(CancellationSignal signal) {
+ Log.i(TAG, "Triggering database backup");
+ backupInternalDatabase(signal);
+ }
+
+ protected void backupInternalDatabase(CancellationSignal signal) {
+ if (!isStableUrisEnabled(MediaStore.VOLUME_INTERNAL)
+ || mInternalDatabase.isDatabaseRecovering()) {
+ return;
+ }
+ setupVolumeDbBackupForInternalIfMissing();
+ FuseDaemon fuseDaemon;
+ try {
+ fuseDaemon = getFuseDaemonForPath("/storage/emulated/" + UserHandle.myUserId());
+ } catch (FileNotFoundException e) {
+ Log.e(TAG,
+ "Fuse Daemon not found for primary external storage, skipping backing up of "
+ + "internal database.",
+ e);
+ return;
+ }
+
+ mInternalDatabase.runWithTransaction((db) -> {
+ try (Cursor c = db.query(true, "files",
+ new String[]{FileColumns._ID, FileColumns.DATA, FileColumns.IS_FAVORITE},
+ null, null, null, null, null,
+ null, signal)) {
+ while (c.moveToNext()) {
+ final long id = c.getLong(0);
+ final String data = c.getString(1);
+ final int isFavorite = c.getInt(2);
+ BackupIdRow.Builder builder = BackupIdRow.newBuilder(id);
+ builder.setIsFavorite(isFavorite);
+ builder.setIsDirty(false);
+ fuseDaemon.backupVolumeDbData(data, BackupIdRow.serialize(builder.build()));
+ }
+ Log.d(TAG,
+ "Backed up data of internal database to external storage on idle "
+ + "maintenance.");
+ } catch (Exception e) {
+ Log.e(TAG, "Failure in backing up internal database to external storage.", e);
+ }
+ return null;
+ });
+ }
+
+ /**
* This function find and clean the files related to user who have been removed
*/
private void cleanMediaFilesForRemovedUser(CancellationSignal signal) {
@@ -6586,11 +6705,58 @@
bundle.putBoolean(MediaStore.USES_FUSE_PASSTHROUGH_RESULT, isEnabled);
return bundle;
}
+ case MediaStore.RUN_IDLE_MAINTENANCE_FOR_STABLE_URIS: {
+ getContext().enforceCallingPermission(Manifest.permission.WRITE_MEDIA_STORAGE,
+ "Permission missing to call RUN_IDLE_MAINTENANCE_FOR_STABLE_URIS by "
+ + "uid:" + Binder.getCallingUid());
+ backupDatabases(null);
+ return new Bundle();
+ }
+ case MediaStore.READ_BACKED_UP_FILE_PATHS: {
+ getContext().enforceCallingPermission(Manifest.permission.WRITE_MEDIA_STORAGE,
+ "Permission missing to call READ_BACKED_UP_FILE_PATHS by "
+ + "uid:" + Binder.getCallingUid());
+ List<String> cumulatedValues = new ArrayList<String>();
+ String[] backedUpFilePaths;
+ String lastReadValue = "";
+ while (true) {
+ backedUpFilePaths = readBackedUpFilePaths(arg, lastReadValue,
+ LEVEL_DB_READ_LIMIT);
+ if (backedUpFilePaths.length <= 0) {
+ break;
+ }
+ cumulatedValues.addAll(Arrays.asList(backedUpFilePaths));
+ if (backedUpFilePaths.length < LEVEL_DB_READ_LIMIT) {
+ break;
+ }
+ lastReadValue = backedUpFilePaths[backedUpFilePaths.length - 1];
+ }
+
+ Bundle bundle = new Bundle();
+ Object[] values = cumulatedValues.toArray();
+ String[] resultArray = Arrays.copyOf(values, values.length, String[].class);
+ bundle.putStringArray(READ_BACKED_UP_FILE_PATHS, resultArray);
+ return bundle;
+ }
+ case MediaStore.DELETE_BACKED_UP_FILE_PATHS:
+ getContext().enforceCallingPermission(Manifest.permission.WRITE_MEDIA_STORAGE,
+ "Permission missing to call DELETE_BACKED_UP_FILE_PATHS by "
+ + "uid:" + Binder.getCallingUid());
+ deleteBackupForVolume(arg);
+ return new Bundle();
default:
throw new UnsupportedOperationException("Unsupported call: " + method);
}
}
+ private void deleteBackupForVolume(String volumeName) {
+ File dbFilePath = new File(
+ String.format(Locale.ROOT, "%s/%s.db", sRecoveryDirectoryPath, volumeName));
+ if (dbFilePath.exists()) {
+ dbFilePath.delete();
+ }
+ }
+
private void syncAllMedia() {
// Clear the binder calling identity so that we can sync the unexported
// local_provider while running as MediaProvider
@@ -8063,6 +8229,45 @@
.withAppendedId(Images.Media.getContentUri(volumeName), imageId);
return ensureThumbnail(targetUri, signal);
}
+ case CLI: {
+ // Command Line Interface "file" - content://media/cli - may be opened only by
+ // Shell (or Root).
+ if (!isCallingPackageShell()) {
+ throw new SecurityException("Only shell (or root) is allowed to open "
+ + "MediaProvider's CLI file (" + uri + ')');
+ }
+
+ // We expect the uri's query to hold a single parameter - "cmd" - which contains
+ // the command name followed by the arguments (if any), all joined with '+'
+ // symbols:
+ // ?cmd=command[+arg1+[arg2+[arg3...]]]
+ //
+ // For example:
+ // (1) ?cmd=version
+ // (2) ?cmd=set-cloud-provider=com.my.cloud.provider.authority
+ //
+ // We retrieve the command name and the argument (if any) with
+ // uri.getQueryParameter("cmd") call, which will replace all '+' delimiters with
+ // spaces.
+
+ final String[] cmdAndArgs = uri.getQueryParameter("cmd").split("\\s+");
+ Log.d(TAG, "MediaProvider CLI command: " + Arrays.toString(cmdAndArgs));
+ try {
+ // Create a UNIX pipe.
+ final ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
+ // Pass the write end - pipe[1] - to our shell command.
+ final var cmd = new MediaProviderShellCommand(getContext(),
+ mConfigStore,
+ mPickerSyncController,
+ /* out */ pipe[1]);
+ cmd.exec(cmdAndArgs);
+ // Return the read end - pipe[0] - to the caller.
+ return pipe[0];
+ } catch (IOException e) {
+ Log.e(TAG, "Could not create a pipe", e);
+ return null;
+ }
+ }
}
} finally {
// We have to log separately here because openFileAndEnforcePathPermissionsHelper calls
@@ -10378,12 +10583,23 @@
return uri;
}
+ /**
+ * On device boot, leveldb setup is done as part of attachVolume call for primary external.
+ * Also, on device config flag change, we check if flag is enabled, if yes, we proceed to
+ * setup(no-op if connection already exists). So, we setup backup and recovery for internal
+ * volume on Media mount signal of EXTERNAL_PRIMARY.
+ */
private void setupVolumeDbBackupAndRecovery(MediaVolume volume) {
- if (MediaStore.VOLUME_INTERNAL.equalsIgnoreCase(volume.getName())) {
- // Leveldb setup for internal volume is done during leveldb setup for primary external.
+ // We are setting up leveldb instance only for internal volume as of now. Since internal
+ // volume does not have any fuse daemon thread, leveldb instance is created by fuse
+ // daemon thread of EXTERNAL_PRIMARY.
+ if (!MediaStore.VOLUME_EXTERNAL_PRIMARY.equalsIgnoreCase(volume.getName())) {
+ // Set backup only for external primary for now.
return;
}
- if (!mConfigStore.isStableUrisForInternalVolumeEnabled()) {
+ // Do not create leveldb instance if stable uris is not enabled for internal volume.
+ if (!isStableUrisEnabled(MediaStore.VOLUME_INTERNAL)) {
+ // Return if we are not supporting backup for internal volume
return;
}
@@ -10393,11 +10609,23 @@
}
getFuseDaemonForFile(volume.getPath()).setupVolumeDbBackup();
} catch (IOException e) {
- Log.w(TAG, "Failure in setting up backup and recovery for volume: " + volume.getName(),
+ Log.e(TAG, "Failure in setting up backup and recovery for volume: " + volume.getName(),
e);
}
}
+ private void setupVolumeDbBackupForInternalIfMissing() {
+ try {
+ if (!new File(sRecoveryDirectoryPath).exists()) {
+ new File(sRecoveryDirectoryPath).mkdirs();
+ }
+ final String fuseDaemonFilePath = "/storage/emulated/" + UserHandle.myUserId();
+ getFuseDaemonForPath(fuseDaemonFilePath).setupVolumeDbBackup();
+ } catch (IOException e) {
+ Log.e(TAG, "Failure in setting up backup and recovery for internal database.", e);
+ }
+ }
+
/**
* Returns true if migration and recovery code flow for stable uris is enabled for given volume.
*/
@@ -10538,6 +10766,9 @@
static final int PICKER_INTERNAL_ALBUMS = 903;
static final int PICKER_UNRELIABLE_VOLUME = 904;
+ // MediaProvider Command Line Interface
+ static final int CLI = 100_000;
+
private static final HashSet<Integer> REDACTED_URI_SUPPORTED_TYPES = new HashSet<>(
Arrays.asList(AUDIO_MEDIA_ID, IMAGES_MEDIA_ID, VIDEO_MEDIA_ID, FILES_ID, DOWNLOADS_ID));
@@ -10592,6 +10823,9 @@
mPublic.addURI(auth, "picker/#/*/media/*", PICKER_ID);
// content://media/picker/unreliable/<media_id>
mPublic.addURI(auth, "picker/unreliable/#", PICKER_UNRELIABLE_VOLUME);
+
+ mPublic.addURI(auth, "cli", CLI);
+
mPublic.addURI(auth, "*/images/media", IMAGES_MEDIA);
mPublic.addURI(auth, "*/images/media/#", IMAGES_MEDIA_ID);
mPublic.addURI(auth, "*/images/media/#/thumbnail", IMAGES_MEDIA_ID_THUMBNAIL);
diff --git a/src/com/android/providers/media/MediaProviderShellCommand.java b/src/com/android/providers/media/MediaProviderShellCommand.java
new file mode 100644
index 0000000..d0fd186
--- /dev/null
+++ b/src/com/android/providers/media/MediaProviderShellCommand.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.media;
+
+import static android.os.Process.THREAD_PRIORITY_FOREGROUND;
+
+import static com.android.providers.media.photopicker.util.CloudProviderUtils.getAllAvailableCloudProviders;
+import static com.android.providers.media.photopicker.util.CloudProviderUtils.getAvailableCloudProviders;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.ParcelFileDescriptor;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.modules.utils.BasicShellCommandHandler;
+import com.android.modules.utils.HandlerExecutor;
+import com.android.providers.media.photopicker.PickerSyncController;
+import com.android.providers.media.photopicker.data.CloudProviderInfo;
+import com.android.providers.media.photopicker.data.PickerDatabaseHelper;
+
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+class MediaProviderShellCommand extends BasicShellCommandHandler {
+ private final @NonNull Context mAppContext;
+ private final @NonNull ConfigStore mConfigStore;
+ private final @NonNull PickerSyncController mPickerSyncController;
+ private final @NonNull OutputStream mOut;
+
+ MediaProviderShellCommand(
+ @NonNull Context context,
+ @NonNull ConfigStore configStore,
+ @NonNull PickerSyncController pickerSyncController,
+ @NonNull ParcelFileDescriptor out) {
+ mAppContext = context.getApplicationContext();
+ mPickerSyncController = pickerSyncController;
+ mConfigStore = configStore;
+ mOut = new ParcelFileDescriptor.AutoCloseOutputStream(out);
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ try (PrintWriter pw = getOutPrintWriter()) {
+ if (cmd == null || cmd.isBlank()) {
+ cmd = "help";
+ }
+ switch (cmd) {
+ case "version":
+ return runVersion(pw);
+ case "cloud-provider":
+ return runCloudProvider(pw);
+ default:
+ return handleDefaultCommands(cmd);
+ }
+ }
+ }
+
+ private int runVersion(@NonNull PrintWriter pw) {
+ pw.print('\'' + DatabaseHelper.INTERNAL_DATABASE_NAME + "' version: ");
+ pw.println(DatabaseHelper.VERSION_LATEST);
+
+ pw.print('\'' + DatabaseHelper.EXTERNAL_DATABASE_NAME + "' version: ");
+ pw.println(DatabaseHelper.VERSION_LATEST);
+
+ pw.print('\'' + PickerDatabaseHelper.PICKER_DATABASE_NAME + "' version: ");
+ pw.println(PickerDatabaseHelper.VERSION_LATEST);
+
+ return 0;
+ }
+
+ private int runCloudProvider(@NonNull PrintWriter pw) {
+ final String subcommand = getNextArgRequired();
+ switch (subcommand) {
+ case "list":
+ return runCloudProviderList(pw);
+ case "info":
+ return runCloudProviderInfo(pw);
+ case "set":
+ return runCloudProviderSet(pw);
+ case "unset":
+ return runCloudProviderUnset(pw);
+ case "sync-library":
+ return runCloudProviderSyncLibrary(pw);
+ case "reset-library":
+ return runCloudProviderResetLibrary(pw);
+ default:
+ pw.println("Error: unknown cloud-provider command '" + subcommand + "'");
+ return 1;
+ }
+ }
+
+ private int runCloudProviderList(@NonNull PrintWriter pw) {
+ final String option = getNextOption();
+ if ("--allowlist".equals(option)) {
+ final List<String> allowlist = mConfigStore.getAllowlistedCloudProviders();
+ if (allowlist.isEmpty()) {
+ pw.println("Allowlist is empty.");
+ } else {
+ for (var providerAuthority : allowlist) {
+ pw.println(providerAuthority);
+ }
+ }
+ } else {
+ final List<CloudProviderInfo> cloudProviders;
+
+ if ("--all".equals(option)) {
+ cloudProviders = getAllAvailableCloudProviders(mAppContext, mConfigStore);
+ } else if (option == null) {
+ cloudProviders = getAvailableCloudProviders(mAppContext, mConfigStore);
+ } else {
+ pw.println("Error: unknown cloud-provider list option '" + option + "'");
+ return 1;
+ }
+
+ if (cloudProviders.isEmpty()) {
+ pw.println("No available CloudMediaProviders.");
+ } else {
+ for (var providerInfo : cloudProviders) {
+ pw.println(providerInfo.toShortString());
+ }
+ }
+ }
+ return 0;
+ }
+
+ private int runCloudProviderInfo(@NonNull PrintWriter pw) {
+ pw.println("Current CloudMediaProvider:");
+ pw.println(mPickerSyncController.getCurrentCloudProviderInfo().toShortString());
+ return 0;
+ }
+
+ private int runCloudProviderSet(@NonNull PrintWriter pw) {
+ final String authority = getNextArg();
+ if (authority == null) {
+ pw.println("Error: authority not provided");
+ pw.println("(usage: `media_provider cloud-provider set <authority>`)");
+ return 1;
+ }
+
+ pw.println("Setting current CloudMediaProvider authority to '" + authority + "'...");
+ final boolean success = mPickerSyncController.forceSetCloudProvider(authority);
+
+ pw.println(success ? "Succeed." : "Failed.");
+ return success ? 0 : 1;
+ }
+
+ private int runCloudProviderUnset(@NonNull PrintWriter pw) {
+ pw.println("Unsetting current CloudMediaProvider (disabling CMP integration)...");
+ final boolean success = mPickerSyncController.forceSetCloudProvider(null);
+
+ pw.println(success ? "Succeed." : "Failed.");
+ return success ? 0 : 1;
+ }
+
+ private int runCloudProviderSyncLibrary(@NonNull PrintWriter pw) {
+ pw.println("Syncing PhotoPicker's library (CMP and local)...");
+
+ // TODO(b/242550131): add PickerSyncController's API to make it possible to sync from only
+ // one provider at a time (i.e. either CMP or local)
+ mPickerSyncController.syncAllMedia();
+
+ pw.println("Done.");
+ return 0;
+ }
+
+ private int runCloudProviderResetLibrary(@NonNull PrintWriter pw) {
+ pw.println("Resetting PhotoPicker's library (CMP and local)...");
+
+ // TODO(b/242550131): add PickerSyncController's API to make it possible to reset just one
+ // provider's library at a time (i.e. either CMP or local).
+ mPickerSyncController.resetAllMedia();
+
+ pw.println("Done.");
+ return 0;
+ }
+
+ @Override
+ public void onHelp() {
+ final PrintWriter pw = getOutPrintWriter();
+ pw.println("MediaProvider (media_provider) commands:");
+ pw.println(" help");
+ pw.println(" Print this help text.");
+ pw.println();
+ pw.println(" version");
+ pw.println(" Print databases (internal/external/picker) versions.");
+ pw.println();
+ pw.println(" cloud-provider [list | info | set | unset] [...]");
+ pw.println(" Configure and audit CloudMediaProvider-s (CMPs).");
+ pw.println();
+ pw.println(" list [--all | --allowlist]");
+ pw.println(" List installed and allowlisted CMPs.");
+ pw.println(" --all: ignore allowlist, list all installed CMPs.");
+ pw.println(" --allowlisted: print allowlist of CMP authorities.");
+ pw.println();
+ pw.println(" info");
+ pw.println(" Print current CloudMediaProvider.");
+ pw.println();
+ pw.println(" set <AUTHORITY>");
+ pw.println(" Set current CloudMediaProvider.");
+ pw.println();
+ pw.println(" unset");
+ pw.println(" Unset CloudMediaProvider (disables CMP integration).");
+ pw.println();
+ pw.println(" sync-library");
+ pw.println(" Sync media from the current CloudMediaProvider and local provider.");
+ pw.println();
+ pw.println(" reset-library");
+ pw.println(" Reset media previously synced from the CloudMediaProvider and");
+ pw.println(" the local provider.");
+ pw.println();
+ }
+
+ public void exec(@Nullable String[] args) {
+ getExecutor().execute(() -> exec(
+ /* Binder target */ null,
+ /* FileDescriptor in */ null,
+ /* FileDescriptor out */ null,
+ /* FileDescriptor err */ null,
+ args));
+ }
+
+
+ @Override
+ public OutputStream getRawOutputStream() {
+ return mOut;
+ }
+
+ @Override
+ public OutputStream getRawErrorStream() {
+ return mOut;
+ }
+
+ @Nullable
+ private static Executor sExecutor;
+
+ @NonNull
+ private static synchronized Executor getExecutor() {
+ if (sExecutor == null) {
+ final HandlerThread thread = new HandlerThread("cli", THREAD_PRIORITY_FOREGROUND);
+ thread.start();
+ final Handler handler = new Handler(thread.getLooper());
+ sExecutor = new HandlerExecutor(handler);
+ }
+ return sExecutor;
+ }
+}
diff --git a/src/com/android/providers/media/MediaReceiver.java b/src/com/android/providers/media/MediaReceiver.java
index a10a71d..0558afe 100644
--- a/src/com/android/providers/media/MediaReceiver.java
+++ b/src/com/android/providers/media/MediaReceiver.java
@@ -22,6 +22,8 @@
import android.content.Context;
import android.content.Intent;
+import com.android.providers.media.stableuris.job.StableUriIdleMaintenanceService;
+
public class MediaReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
@@ -29,7 +31,7 @@
if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
// Register our idle maintenance service
IdleService.scheduleIdlePass(context);
-
+ StableUriIdleMaintenanceService.scheduleIdlePass(context);
} else {
// All other operations are heavier-weight, so redirect them through
// service to ensure they have breathing room to finish
diff --git a/src/com/android/providers/media/photopicker/PickerSyncController.java b/src/com/android/providers/media/photopicker/PickerSyncController.java
index 3d0cf14..a92eb00 100644
--- a/src/com/android/providers/media/photopicker/PickerSyncController.java
+++ b/src/com/android/providers/media/photopicker/PickerSyncController.java
@@ -49,6 +49,7 @@
import androidx.annotation.GuardedBy;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.modules.utils.BackgroundThread;
@@ -207,9 +208,25 @@
}
}
+ /**
+ * Resets media library previously synced from the current {@link CloudMediaProvider} as well
+ * as the {@link #mLocalProvider local provider}.
+ */
+ public void resetAllMedia() {
+ resetAllMedia(mLocalProvider, /* isLocal */ true);
+ synchronized (mLock) {
+ resetAllMedia(mCloudProviderInfo.authority, /* isLocal */ false);
+ }
+ }
+
private void resetAllMedia(String authority, boolean isLocal) {
- executeSyncReset(authority, isLocal);
- resetCachedMediaCollectionInfo(authority, isLocal);
+ Trace.beginSection(traceSectionName("resetAllMedia", isLocal));
+ try {
+ executeSyncReset(authority, isLocal);
+ resetCachedMediaCollectionInfo(authority, isLocal);
+ } finally {
+ Trace.endSection();
+ }
}
@NonNull
@@ -248,9 +265,9 @@
* background after switching providers.
*
* @return {@code true} if the provider was successfully enabled or cleared, {@code false}
- * otherwise
+ * otherwise.
*/
- public boolean setCloudProvider(String authority) {
+ public boolean setCloudProvider(@Nullable String authority) {
Trace.beginSection(traceSectionName("setCloudProvider"));
try {
return setCloudProviderInternal(authority, /* ignoreAllowlist */ false);
@@ -261,18 +278,20 @@
/**
* Set cloud provider ignoring allowlist.
+ *
+ * @return {@code true} if the provider was successfully enabled or cleared, {@code false}
+ * otherwise.
*/
- @VisibleForTesting
- public void forceSetCloudProvider(String authority) {
+ public boolean forceSetCloudProvider(@Nullable String authority) {
Trace.beginSection(traceSectionName("forceSetCloudProvider"));
try {
- setCloudProviderInternal(authority, /* ignoreAllowlist */ true);
+ return setCloudProviderInternal(authority, /* ignoreAllowlist */ true);
} finally {
Trace.endSection();
}
}
- private boolean setCloudProviderInternal(String authority, boolean ignoreAllowList) {
+ private boolean setCloudProviderInternal(@Nullable String authority, boolean ignoreAllowList) {
synchronized (mLock) {
if (Objects.equals(mCloudProviderInfo.authority, authority)) {
Log.w(TAG, "Cloud provider already set: " + authority);
@@ -307,12 +326,34 @@
return false;
}
+ /**
+ * @return {@link CloudProviderInfo} for the current {@link CloudMediaProvider} or
+ * {@link CloudProviderInfo#EMPTY} if the {@link CloudMediaProvider} integration is not
+ * enabled.
+ */
+ @NonNull
+ public CloudProviderInfo getCurrentCloudProviderInfo() {
+ synchronized (mLock) {
+ return mCloudProviderInfo;
+ }
+ }
+
+ /**
+ * @return {@link android.content.pm.ProviderInfo#authority authority} of the current
+ * {@link CloudMediaProvider} or {@code null} if the {@link CloudMediaProvider}
+ * integration is not enabled.
+ */
+ @Nullable
public String getCloudProvider() {
synchronized (mLock) {
return mCloudProviderInfo.authority;
}
}
+ /**
+ * @return {@link android.content.pm.ProviderInfo#authority authority} of the local provider.
+ */
+ @NonNull
public String getLocalProvider() {
return mLocalProvider;
}
diff --git a/src/com/android/providers/media/photopicker/data/CloudProviderInfo.java b/src/com/android/providers/media/photopicker/data/CloudProviderInfo.java
index 5fa6370..e32346b 100644
--- a/src/com/android/providers/media/photopicker/data/CloudProviderInfo.java
+++ b/src/com/android/providers/media/photopicker/data/CloudProviderInfo.java
@@ -86,4 +86,12 @@
+ ", uid=" + uid
+ '}';
}
+
+ /** Returns a short string representation of the object. */
+ public String toShortString() {
+ if (isEmpty()) {
+ return "-";
+ }
+ return "pkg: " + packageName + " / auth: " + authority;
+ }
}
diff --git a/src/com/android/providers/media/photopicker/data/PickerDatabaseHelper.java b/src/com/android/providers/media/photopicker/data/PickerDatabaseHelper.java
index 2310934..bbd0c21 100644
--- a/src/com/android/providers/media/photopicker/data/PickerDatabaseHelper.java
+++ b/src/com/android/providers/media/photopicker/data/PickerDatabaseHelper.java
@@ -36,11 +36,10 @@
public class PickerDatabaseHelper extends SQLiteOpenHelper {
private static final String TAG = "PickerDatabaseHelper";
- @VisibleForTesting
- static final String PICKER_DATABASE_NAME = "picker.db";
+ public static final String PICKER_DATABASE_NAME = "picker.db";
private static final int VERSION_T = 8;
- private static final int VERSION_LATEST = VERSION_T;
+ public static final int VERSION_LATEST = VERSION_T;
final Context mContext;
final String mName;
diff --git a/src/com/android/providers/media/photopicker/data/model/Item.java b/src/com/android/providers/media/photopicker/data/model/Item.java
index 7983555..eee2e83 100644
--- a/src/com/android/providers/media/photopicker/data/model/Item.java
+++ b/src/com/android/providers/media/photopicker/data/model/Item.java
@@ -25,12 +25,11 @@
import static com.android.providers.media.photopicker.util.CursorUtils.getCursorLong;
import static com.android.providers.media.photopicker.util.CursorUtils.getCursorString;
+import static java.util.Objects.requireNonNull;
+
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
-import android.os.Bundle;
-import android.provider.CloudMediaProviderContract;
-import android.provider.MediaStore;
import android.text.format.DateUtils;
import androidx.annotation.NonNull;
@@ -42,7 +41,7 @@
import com.android.providers.media.util.MimeUtils;
/**
- * Base class representing one single entity/item in the PhotoPicker.
+ * Base class for representing a single media item (a picture, a video, etc.) in the PhotoPicker.
*/
public class Item {
private String mId;
@@ -54,9 +53,6 @@
private boolean mIsImage;
private boolean mIsVideo;
private int mSpecialFormat;
- private boolean mIsDate;
-
- private Item() {}
public Item(@NonNull Cursor cursor, @NonNull UserId userId) {
updateFromCursor(cursor, userId);
@@ -103,10 +99,6 @@
return mSpecialFormat == _SPECIAL_FORMAT_MOTION_PHOTO;
}
- public boolean isDate() {
- return mIsDate;
- }
-
public Uri getContentUri() {
return mUri;
}
@@ -132,23 +124,8 @@
return mSpecialFormat;
}
- public static Item fromCursor(Cursor cursor, UserId userId) {
- assert(cursor != null);
- final Item item = new Item(cursor, userId);
- return item;
- }
-
- /**
- * Return the date item. If dateTaken is 0, it is a recent item.
- * @param dateTaken the time of date taken. The unit is in milliseconds
- * since January 1, 1970 00:00:00.0 UTC.
- * @return the item with date type
- */
- public static Item createDateItem(long dateTaken) {
- final Item item = new Item();
- item.mIsDate = true;
- item.mDateTaken = dateTaken;
- return item;
+ public static Item fromCursor(@NonNull Cursor cursor, UserId userId) {
+ return new Item(requireNonNull(cursor), userId);
}
/**
diff --git a/src/com/android/providers/media/photopicker/ui/DateHeaderHolder.java b/src/com/android/providers/media/photopicker/ui/DateHeaderHolder.java
deleted file mode 100644
index 0c6dc4a..0000000
--- a/src/com/android/providers/media/photopicker/ui/DateHeaderHolder.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.providers.media.photopicker.ui;
-import android.content.Context;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-
-import com.android.providers.media.R;
-import com.android.providers.media.photopicker.util.DateTimeUtils;
-import com.android.providers.media.photopicker.data.model.Item;
-
-/**
- * ViewHolder of a date header within a RecyclerView.
- */
-public class DateHeaderHolder extends BaseViewHolder {
- private TextView mTitle;
- public DateHeaderHolder(@NonNull Context context, @NonNull ViewGroup parent) {
- super(context, parent, R.layout.item_date_header);
- mTitle = itemView.findViewById(R.id.date_header_title);
- }
-
- @Override
- public void bind() {
- final Item item = (Item) itemView.getTag();
- final long dateTaken = item.getDateTaken();
- if (dateTaken == 0) {
- mTitle.setText(R.string.recent);
- } else {
- mTitle.setText(DateTimeUtils.getDateHeaderString(dateTaken));
- }
- }
-}
diff --git a/src/com/android/providers/media/photopicker/ui/MediaItemGridViewHolder.java b/src/com/android/providers/media/photopicker/ui/MediaItemGridViewHolder.java
new file mode 100644
index 0000000..f149955
--- /dev/null
+++ b/src/com/android/providers/media/photopicker/ui/MediaItemGridViewHolder.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.media.photopicker.ui;
+
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
+
+import android.content.Context;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.providers.media.R;
+import com.android.providers.media.photopicker.data.model.Item;
+
+/**
+ * {@link RecyclerView.ViewHolder} of a {@link View} representing a (media) {@link Item} (a photo or
+ * a video).
+ */
+class MediaItemGridViewHolder extends RecyclerView.ViewHolder {
+ private final ImageLoader mImageLoader;
+ private final ImageView mIconThumb;
+ private final ImageView mIconGif;
+ private final ImageView mIconMotionPhoto;
+ private final View mVideoBadgeContainer;
+ private final TextView mVideoDuration;
+ private final View mOverlayGradient;
+ private final boolean mCanSelectMultiple;
+
+ MediaItemGridViewHolder(@NonNull View itemView, @NonNull ImageLoader imageLoader,
+ boolean canSelectMultiple) {
+ super(itemView);
+ mIconThumb = itemView.findViewById(R.id.icon_thumbnail);
+ mIconGif = itemView.findViewById(R.id.icon_gif);
+ mIconMotionPhoto = itemView.findViewById(R.id.icon_motion_photo);
+ mVideoBadgeContainer = itemView.findViewById(R.id.video_container);
+ mVideoDuration = mVideoBadgeContainer.findViewById(R.id.video_duration);
+ mOverlayGradient = itemView.findViewById(R.id.overlay_gradient);
+ mImageLoader = imageLoader;
+ mCanSelectMultiple = canSelectMultiple;
+
+ itemView.findViewById(R.id.icon_check).setVisibility(mCanSelectMultiple ? VISIBLE : GONE);
+ }
+
+ public void bind(@NonNull Item item, boolean isSelected) {
+ mImageLoader.loadPhotoThumbnail(item, mIconThumb);
+
+ mIconGif.setVisibility(item.isGifOrAnimatedWebp() ? VISIBLE : GONE);
+ mIconMotionPhoto.setVisibility(item.isMotionPhoto() ? VISIBLE : GONE);
+
+ if (item.isVideo()) {
+ mVideoBadgeContainer.setVisibility(VISIBLE);
+ mVideoDuration.setText(item.getDurationText());
+ } else {
+ mVideoBadgeContainer.setVisibility(GONE);
+ }
+
+ if (showShowOverlayGradient(item)) {
+ mOverlayGradient.setVisibility(VISIBLE);
+ } else {
+ mOverlayGradient.setVisibility(GONE);
+ }
+
+ final Context context = getContext();
+ itemView.setContentDescription(item.getContentDescription(context));
+
+ if (mCanSelectMultiple) {
+ itemView.setSelected(isSelected);
+ // There is an issue b/223695510 about not selected in Accessibility mode. It only
+ // says selected state, but it doesn't say not selected state. Add the not selected
+ // only to avoid that it says selected twice.
+ itemView.setStateDescription(
+ isSelected ? null : context.getString(R.string.not_selected));
+ }
+ }
+
+ @NonNull
+ private Context getContext() {
+ return itemView.getContext();
+ }
+
+ private boolean showShowOverlayGradient(@NonNull Item item) {
+ return mCanSelectMultiple
+ || item.isGifOrAnimatedWebp()
+ || item.isVideo()
+ || item.isMotionPhoto();
+ }
+}
diff --git a/src/com/android/providers/media/photopicker/ui/PhotoGridHolder.java b/src/com/android/providers/media/photopicker/ui/PhotoGridHolder.java
deleted file mode 100644
index 99d06d7..0000000
--- a/src/com/android/providers/media/photopicker/ui/PhotoGridHolder.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.providers.media.photopicker.ui;
-
-import android.content.Context;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-
-import com.android.providers.media.R;
-import com.android.providers.media.photopicker.data.model.Item;
-
-/**
- * ViewHolder of a photo item within a RecyclerView.
- */
-public class PhotoGridHolder extends BaseViewHolder {
-
- private final ImageLoader mImageLoader;
- private final ImageView mIconThumb;
- private final ImageView mIconGif;
- private final ImageView mIconMotionPhoto;
- private final View mVideoBadgeContainer;
- private final TextView mVideoDuration;
- private final View mOverlayGradient;
- private final boolean mCanSelectMultiple;
-
- public PhotoGridHolder(@NonNull Context context, @NonNull ViewGroup parent,
- @NonNull ImageLoader imageLoader, boolean canSelectMultiple) {
- super(context, parent, R.layout.item_photo_grid);
-
- mIconThumb = itemView.findViewById(R.id.icon_thumbnail);
- mIconGif = itemView.findViewById(R.id.icon_gif);
- mIconMotionPhoto = itemView.findViewById(R.id.icon_motion_photo);
- mVideoBadgeContainer = itemView.findViewById(R.id.video_container);
- mVideoDuration = mVideoBadgeContainer.findViewById(R.id.video_duration);
- mOverlayGradient = itemView.findViewById(R.id.overlay_gradient);
- mImageLoader = imageLoader;
- final ImageView iconCheck = itemView.findViewById(R.id.icon_check);
- mCanSelectMultiple = canSelectMultiple;
- if (mCanSelectMultiple) {
- iconCheck.setVisibility(View.VISIBLE);
- } else {
- iconCheck.setVisibility(View.GONE);
- }
- }
-
- @Override
- public void bind() {
- final Item item = (Item) itemView.getTag();
- mImageLoader.loadPhotoThumbnail(item, mIconThumb);
-
- mIconGif.setVisibility(item.isGifOrAnimatedWebp() ? View.VISIBLE : View.GONE);
- mIconMotionPhoto.setVisibility(item.isMotionPhoto() ? View.VISIBLE : View.GONE);
-
- if (item.isVideo()) {
- mVideoBadgeContainer.setVisibility(View.VISIBLE);
- mVideoDuration.setText(item.getDurationText());
- } else {
- mVideoBadgeContainer.setVisibility(View.GONE);
- }
-
- if (showShowOverlayGradient(item)) {
- mOverlayGradient.setVisibility(View.VISIBLE);
- } else {
- mOverlayGradient.setVisibility(View.GONE);
- }
- }
-
- private boolean showShowOverlayGradient(@NonNull Item item) {
- return mCanSelectMultiple || item.isGifOrAnimatedWebp() || item.isVideo() ||
- item.isMotionPhoto();
- }
-}
diff --git a/src/com/android/providers/media/photopicker/ui/PhotosTabAdapter.java b/src/com/android/providers/media/photopicker/ui/PhotosTabAdapter.java
index f1bfdef..3476d6e 100644
--- a/src/com/android/providers/media/photopicker/ui/PhotosTabAdapter.java
+++ b/src/com/android/providers/media/photopicker/ui/PhotosTabAdapter.java
@@ -16,106 +16,149 @@
package com.android.providers.media.photopicker.ui;
-import android.content.Context;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.TextView;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.android.providers.media.R;
-
import com.android.providers.media.photopicker.data.Selection;
import com.android.providers.media.photopicker.data.model.Item;
+import com.android.providers.media.photopicker.util.DateTimeUtils;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
/**
* Adapts from model to something RecyclerView understands.
*/
-public class PhotosTabAdapter extends RecyclerView.Adapter<BaseViewHolder> {
+class PhotosTabAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
+ static final int ITEM_TYPE_DATE_HEADER = 0;
+ static final int ITEM_TYPE_PHOTO = 1;
- public static final int ITEM_TYPE_DATE_HEADER = 0;
- private static final int ITEM_TYPE_PHOTO = 1;
+ private static final int RECENT_MINIMUM_COUNT = 12;
- public static final int COLUMN_COUNT = 3;
-
- private List<Item> mItemList = new ArrayList<>();
+ private final boolean mShowRecentSection;
+ /**
+ * List of {@link com.android.providers.media.photopicker.data.model.Item Item} and
+ * {@link DateHeader} objects.
+ */
+ private List<Object> mItems = new ArrayList<>();
private final ImageLoader mImageLoader;
- private final View.OnClickListener mOnClickListener;
- private final View.OnLongClickListener mOnLongClickListener;
+ private final View.OnClickListener mOnMediaItemClickListener;
+ private final View.OnLongClickListener mOnMediaItemLongClickListener;
private final Selection mSelection;
- public PhotosTabAdapter(@NonNull Selection selection, @NonNull ImageLoader imageLoader,
- @NonNull View.OnClickListener onClickListener,
- @NonNull View.OnLongClickListener onLongClickListener) {
+ PhotosTabAdapter(boolean showRecentSection,
+ @NonNull Selection selection,
+ @NonNull ImageLoader imageLoader,
+ @NonNull View.OnClickListener onMediaItemClickListener,
+ @NonNull View.OnLongClickListener onMediaItemLongClickListener) {
+ mShowRecentSection = showRecentSection;
mImageLoader = imageLoader;
mSelection = selection;
- mOnClickListener = onClickListener;
- mOnLongClickListener = onLongClickListener;
+ mOnMediaItemClickListener = onMediaItemClickListener;
+ mOnMediaItemLongClickListener = onMediaItemLongClickListener;
}
@NonNull
@Override
- public BaseViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
+ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
+ final LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
if (viewType == ITEM_TYPE_DATE_HEADER) {
- return new DateHeaderHolder(viewGroup.getContext(), viewGroup);
+ final View view = inflater.inflate(R.layout.item_date_header, viewGroup, false);
+ return new DateHeaderViewHolder(view);
+ } else /* viewType == ITEM_TYPE_PHOTO */ {
+ final View view = inflater.inflate(R.layout.item_photo_grid, viewGroup, false);
+ view.setOnClickListener(mOnMediaItemClickListener);
+ view.setOnLongClickListener(mOnMediaItemLongClickListener);
+
+ return new MediaItemGridViewHolder(view, mImageLoader, mSelection.canSelectMultiple());
}
- return new PhotoGridHolder(viewGroup.getContext(), viewGroup, mImageLoader,
- mSelection.canSelectMultiple());
}
@Override
- public void onBindViewHolder(@NonNull BaseViewHolder itemHolder, int position) {
- final Item item = getItem(position);
- itemHolder.itemView.setTag(item);
+ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
+ if (viewHolder instanceof DateHeaderViewHolder) {
+ final DateHeader dateHeader = (DateHeader) getAdapterItem(position);
+ final DateHeaderViewHolder dateHeaderVH = (DateHeaderViewHolder) viewHolder;
- if (getItemViewType(position) == ITEM_TYPE_PHOTO) {
- itemHolder.itemView.setOnClickListener(mOnClickListener);
- itemHolder.itemView.setOnLongClickListener(mOnLongClickListener);
+ dateHeaderVH.bind(dateHeader);
+ } else /* viewHolder instanceof MediaItemGridViewHolder */ {
+ final Item item = (Item) getAdapterItem(position);
+ final MediaItemGridViewHolder mediaItemVH = (MediaItemGridViewHolder) viewHolder;
- final Context context = itemHolder.itemView.getContext();
- itemHolder.itemView.setContentDescription(item.getContentDescription(context));
+ final boolean isSelected = mSelection.canSelectMultiple()
+ && mSelection.isItemSelected(item);
+ mediaItemVH.bind(item, isSelected);
- if (mSelection.canSelectMultiple()) {
- final boolean isSelected = mSelection.isItemSelected(item);
- itemHolder.itemView.setSelected(isSelected);
-
- // There is an issue b/223695510 about not selected in Accessibility mode. It only
- // says selected state, but it doesn't say not selected state. Add the not selected
- // only to avoid that it says selected twice.
- itemHolder.itemView.setStateDescription(
- isSelected ? null : context.getString(R.string.not_selected));
- }
+ // We also need to set Item as a tag so that OnClick/OnLongClickListeners can then
+ // retrieve it.
+ mediaItemVH.itemView.setTag(item);
}
- itemHolder.bind();
}
@Override
public int getItemCount() {
- return mItemList.size();
+ return mItems.size();
}
@Override
public int getItemViewType(int position) {
- if (getItem(position).isDate()) {
+ if (getAdapterItem(position) instanceof Item) {
+ return ITEM_TYPE_PHOTO;
+ } else /* instanceof DateHeader */ {
return ITEM_TYPE_DATE_HEADER;
}
- return ITEM_TYPE_PHOTO;
}
- @NonNull
- public Item getItem(int position) {
- return mItemList.get(position);
- }
+ void setMediaItems(@NonNull List<Item> mediaItems) {
+ if (!mediaItems.isEmpty()) {
+ mItems = new ArrayList<>(mediaItems.size() + 1); // We'll have at least one section
- public void updateItemList(@NonNull List<Item> itemList) {
- mItemList = itemList;
+ // First: show "Recent" section header if needed.
+ if (mShowRecentSection) {
+ mItems.add(new DateHeader(DateHeader.RECENT));
+ }
+
+ int recentItemsCount = 0;
+ long prevItemDate = -1;
+ for (Item mediaItem : mediaItems) {
+ final long itemDate = mediaItem.getDateTaken();
+
+ if (mShowRecentSection && recentItemsCount < RECENT_MINIMUM_COUNT) {
+ // The minimum count of items in "Recent" section is not reached yet.
+ recentItemsCount++;
+ } else if (!DateTimeUtils.isSameDate(prevItemDate, itemDate)) {
+ // The dateTaken of these two images are not on the same day: add a new date
+ // header
+ mItems.add(new DateHeader(itemDate));
+ }
+
+ mItems.add(mediaItem);
+
+ prevItemDate = itemDate;
+ }
+ } else {
+ mItems = Collections.emptyList();
+ }
+
notifyDataSetChanged();
}
+ @Nullable
+ @VisibleForTesting
+ Object getAdapterItem(int position) {
+ return mItems.get(position);
+ }
+
@NonNull
public GridLayoutManager.SpanSizeLookup createSpanSizeLookup(
@NonNull GridLayoutManager layoutManager) {
@@ -133,4 +176,31 @@
}
};
}
+
+ @VisibleForTesting
+ static class DateHeader {
+ static final int RECENT = -1;
+ final long timestamp;
+
+ DateHeader(long timestamp) {
+ this.timestamp = timestamp;
+ }
+ }
+
+ private static class DateHeaderViewHolder extends RecyclerView.ViewHolder {
+ final TextView title;
+
+ DateHeaderViewHolder(@NonNull View itemView) {
+ super(itemView);
+ title = itemView.findViewById(R.id.date_header_title);
+ }
+
+ void bind(@NonNull DateHeader dateHeader) {
+ if (dateHeader.timestamp == DateHeader.RECENT) {
+ title.setText(R.string.recent);
+ } else {
+ title.setText(DateTimeUtils.getDateHeaderString(dateHeader.timestamp));
+ }
+ }
+ }
}
diff --git a/src/com/android/providers/media/photopicker/ui/PhotosTabFragment.java b/src/com/android/providers/media/photopicker/ui/PhotosTabFragment.java
index 78a37a3..c17d33f 100644
--- a/src/com/android/providers/media/photopicker/ui/PhotosTabFragment.java
+++ b/src/com/android/providers/media/photopicker/ui/PhotosTabFragment.java
@@ -15,10 +15,11 @@
*/
package com.android.providers.media.photopicker.ui;
-import static com.android.providers.media.photopicker.ui.PhotosTabAdapter.COLUMN_COUNT;
+import static com.android.providers.media.photopicker.util.LayoutModeUtils.MODE_ALBUM_PHOTOS_TAB;
+import static com.android.providers.media.photopicker.util.LayoutModeUtils.MODE_PHOTOS_TAB;
+import android.content.Context;
import android.os.Bundle;
-import android.provider.CloudMediaProviderContract;
import android.text.TextUtils;
import android.view.View;
@@ -30,7 +31,6 @@
import androidx.recyclerview.widget.GridLayoutManager;
import com.android.providers.media.R;
-
import com.android.providers.media.photopicker.PhotoPickerActivity;
import com.android.providers.media.photopicker.data.model.Category;
import com.android.providers.media.photopicker.data.model.Item;
@@ -46,8 +46,8 @@
* Photos tab fragment for showing the photos
*/
public class PhotosTabFragment extends TabFragment {
-
private static final int MINIMUM_SPAN_COUNT = 3;
+ private static final int GRID_COLUMN_COUNT = 3;
private static final String FRAGMENT_TAG = "PhotosTabFragment";
private Category mCategory = Category.DEFAULT;
@@ -66,38 +66,43 @@
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
+ final Context context = getContext();
- final PhotosTabAdapter adapter = new PhotosTabAdapter(mSelection, mImageLoader,
- this::onItemClick, this::onItemLongClick);
+ // We only add the RECENT header on the PhotosTabFragment with CATEGORY_DEFAULT. In this
+ // case, we call this method {loadItems} with null category. When the category is not
+ // empty, we don't show the RECENT header.
+ final boolean showRecentSection = mCategory.isDefault();
+
+ final PhotosTabAdapter adapter = new PhotosTabAdapter(showRecentSection, mSelection,
+ mImageLoader, this::onItemClick, this::onItemLongClick);
setEmptyMessage(R.string.picker_photos_empty_message);
if (mCategory.isDefault()) {
// Set the pane title for A11y
view.setAccessibilityPaneTitle(getString(R.string.picker_photos));
mPickerViewModel.getItems().observe(this, itemList -> {
- adapter.updateItemList(itemList);
+ adapter.setMediaItems(itemList);
// Handle emptyView's visibility
updateVisibilityForEmptyView(/* shouldShowEmptyView */ itemList.size() == 0);
});
} else {
// Set the pane title for A11y
- view.setAccessibilityPaneTitle(mCategory.getDisplayName(getContext()));
+ view.setAccessibilityPaneTitle(mCategory.getDisplayName(context));
mPickerViewModel.getCategoryItems(mCategory).observe(this, itemList -> {
// If the item count of the albums is zero, albums are not shown on the Albums tab.
// The user can't launch the album items page when the album has zero items. So, we
// don't need to show emptyView in the case.
updateVisibilityForEmptyView(/* shouldShowEmptyView */ false);
- adapter.updateItemList(itemList);
+ adapter.setMediaItems(itemList);
});
}
- final GridLayoutManager layoutManager = new GridLayoutManager(getContext(), COLUMN_COUNT);
+ final GridLayoutManager layoutManager = new GridLayoutManager(context, GRID_COLUMN_COUNT);
final GridLayoutManager.SpanSizeLookup lookup = adapter.createSpanSizeLookup(layoutManager);
layoutManager.setSpanSizeLookup(lookup);
- final PhotosTabItemDecoration itemDecoration = new PhotosTabItemDecoration(
- view.getContext());
+ final PhotosTabItemDecoration itemDecoration = new PhotosTabItemDecoration(context);
final int spacing = getResources().getDimensionPixelSize(R.dimen.picker_photo_item_spacing);
final int photoSize = getResources().getDimensionPixelSize(R.dimen.picker_photo_size);
@@ -123,15 +128,21 @@
public void onResume() {
super.onResume();
+ final String title;
+ final LayoutModeUtils.Mode layoutMode;
+ final boolean shouldHideProfileButton;
if (mCategory.isDefault()) {
- ((PhotoPickerActivity) getActivity()).updateCommonLayouts(
- LayoutModeUtils.MODE_PHOTOS_TAB, /* title */ "");
- hideProfileButton(/* hide */ false);
+ title = "";
+ layoutMode = MODE_PHOTOS_TAB;
+ shouldHideProfileButton = false;
} else {
- hideProfileButton(/* hide */ true);
- ((PhotoPickerActivity) getActivity()).updateCommonLayouts(
- LayoutModeUtils.MODE_ALBUM_PHOTOS_TAB, mCategory.getDisplayName(getContext()));
+ title = mCategory.getDisplayName(getContext());
+ layoutMode = MODE_ALBUM_PHOTOS_TAB;
+ shouldHideProfileButton = true;
}
+
+ getPickerActivity().updateCommonLayouts(layoutMode, title);
+ hideProfileButton(shouldHideProfileButton);
}
private void onItemClick(@NonNull View view) {
@@ -153,7 +164,8 @@
Snackbar.make(view, message, Snackbar.LENGTH_SHORT).show();
return;
} else {
- mSelection.addSelectedItem((Item) view.getTag());
+ final Item item = (Item) view.getTag();
+ mSelection.addSelectedItem(item);
}
}
view.setSelected(!isSelectedBefore);
@@ -162,14 +174,14 @@
// avoid that it says selected twice.
view.setStateDescription(isSelectedBefore ? getString(R.string.not_selected) : null);
} else {
- Item item = (Item) view.getTag();
+ final Item item = (Item) view.getTag();
mSelection.setSelectedItem(item);
- ((PhotoPickerActivity) getActivity()).setResultAndFinishSelf();
+ getPickerActivity().setResultAndFinishSelf();
}
}
private boolean onItemLongClick(@NonNull View view) {
- Item item = (Item) view.getTag();
+ final Item item = (Item) view.getTag();
if (!mSelection.canSelectMultiple()) {
// In single select mode, if the item is previewed, we set it as selected item. This is
// will assist in "Add" button click to return all selected items.
@@ -185,6 +197,10 @@
return true;
}
+ private PhotoPickerActivity getPickerActivity() {
+ return (PhotoPickerActivity) getActivity();
+ }
+
/**
* Create the fragment with the category and add it into the FragmentManager
*
diff --git a/src/com/android/providers/media/photopicker/viewmodel/PickerViewModel.java b/src/com/android/providers/media/photopicker/viewmodel/PickerViewModel.java
index 394b0cf..55523dd 100644
--- a/src/com/android/providers/media/photopicker/viewmodel/PickerViewModel.java
+++ b/src/com/android/providers/media/photopicker/viewmodel/PickerViewModel.java
@@ -47,7 +47,6 @@
import com.android.providers.media.photopicker.data.model.Item;
import com.android.providers.media.photopicker.data.model.UserId;
import com.android.providers.media.photopicker.metrics.PhotoPickerUiEventLogger;
-import com.android.providers.media.photopicker.util.DateTimeUtils;
import com.android.providers.media.photopicker.util.MimeFilterUtils;
import com.android.providers.media.util.ForegroundThread;
import com.android.providers.media.util.MimeUtils;
@@ -170,36 +169,10 @@
return items;
}
- // We only add the RECENT header on the PhotosTabFragment with CATEGORY_DEFAULT. In this
- // case, we call this method {loadItems} with null category. When the category is not
- // empty, we don't show the RECENT header.
- final boolean showRecent = category.isDefault();
-
- int recentSize = 0;
- long currentDateTaken = 0;
-
- if (showRecent) {
- // add Recent date header
- items.add(Item.createDateItem(0));
- }
while (cursor.moveToNext()) {
// TODO(b/188394433): Return userId in the cursor so that we do not need to pass it
- // here again.
- final Item item = Item.fromCursor(cursor, userId);
- final long dateTaken = item.getDateTaken();
- // the minimum count of items in recent is not reached
- if (showRecent && recentSize < RECENT_MINIMUM_COUNT) {
- recentSize++;
- currentDateTaken = dateTaken;
- }
-
- // The date taken of these two images are not on the
- // same day, add the new date header.
- if (!DateTimeUtils.isSameDate(currentDateTaken, dateTaken)) {
- items.add(Item.createDateItem(dateTaken));
- currentDateTaken = dateTaken;
- }
- items.add(item);
+ // here again.
+ items.add(Item.fromCursor(cursor, userId));
}
}
diff --git a/src/com/android/providers/media/stableuris/job/StableUriIdleMaintenanceService.java b/src/com/android/providers/media/stableuris/job/StableUriIdleMaintenanceService.java
new file mode 100644
index 0000000..493333f
--- /dev/null
+++ b/src/com/android/providers/media/stableuris/job/StableUriIdleMaintenanceService.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.media.stableuris.job;
+
+import static com.android.providers.media.util.Logging.TAG;
+
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.ComponentName;
+import android.content.ContentProviderClient;
+import android.content.Context;
+import android.os.CancellationSignal;
+import android.os.OperationCanceledException;
+import android.provider.MediaStore;
+import android.util.Log;
+
+import com.android.providers.media.MediaProvider;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Job defining idle maintenance tasks for Stable URIs.
+ */
+public class StableUriIdleMaintenanceService extends JobService {
+ private static final int IDLE_JOB_ID = -500;
+
+ private CancellationSignal mSignal;
+
+ @Override
+ public boolean onStartJob(JobParameters params) {
+ mSignal = new CancellationSignal();
+ new Thread(() -> {
+ try (ContentProviderClient cpc = getContentResolver()
+ .acquireContentProviderClient(MediaStore.AUTHORITY)) {
+ ((MediaProvider) cpc.getLocalContentProvider()).backupDatabases(mSignal);
+ } catch (OperationCanceledException e) {
+ Log.e(TAG, "StableUriIdleMaintenanceService operation cancelled: ", e);
+ }
+ jobFinished(params, false);
+ }).start();
+ return true;
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters params) {
+ mSignal.cancel();
+ return false;
+ }
+
+ /**
+ * Schedules job with {@link JobScheduler}.
+ */
+ public static void scheduleIdlePass(Context context) {
+ final JobScheduler scheduler = context.getSystemService(JobScheduler.class);
+ if (scheduler.getPendingJob(IDLE_JOB_ID) == null) {
+ final JobInfo job = new JobInfo.Builder(IDLE_JOB_ID,
+ new ComponentName(context,
+ StableUriIdleMaintenanceService.class))
+ .setPeriodic(TimeUnit.DAYS.toMillis(7))
+ .setRequiresCharging(true)
+ .setRequiresDeviceIdle(true)
+ .build();
+ scheduler.schedule(job);
+ }
+ }
+}
diff --git a/tests/src/com/android/providers/media/MediaProviderTest.java b/tests/src/com/android/providers/media/MediaProviderTest.java
index fe5d0d3..c089002 100644
--- a/tests/src/com/android/providers/media/MediaProviderTest.java
+++ b/tests/src/com/android/providers/media/MediaProviderTest.java
@@ -681,7 +681,7 @@
}
@Override
- protected void checkConfigAndUpdateGetContentAlias() {
+ protected void storageNativeBootPropertyChangeListener() {
// Ignore this as test app cannot read device config
}
};
@@ -1113,7 +1113,7 @@
}
@Override
- protected void checkConfigAndUpdateGetContentAlias() {
+ protected void storageNativeBootPropertyChangeListener() {
// Ignore this as test app cannot read device config
}
};
diff --git a/tests/src/com/android/providers/media/photopicker/data/SelectionTest.java b/tests/src/com/android/providers/media/photopicker/data/SelectionTest.java
index ec68646..b568a98 100644
--- a/tests/src/com/android/providers/media/photopicker/data/SelectionTest.java
+++ b/tests/src/com/android/providers/media/photopicker/data/SelectionTest.java
@@ -16,6 +16,8 @@
package com.android.providers.media.photopicker.data;
+import static com.android.providers.media.photopicker.data.model.ModelTestUtils.generateJpegItem;
+
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
@@ -30,7 +32,6 @@
import androidx.test.InstrumentationRegistry;
import com.android.providers.media.photopicker.data.model.Item;
-import com.android.providers.media.photopicker.data.model.ItemTest;
import com.android.providers.media.photopicker.viewmodel.InstantTaskExecutorRule;
import com.android.providers.media.photopicker.viewmodel.PickerViewModel;
@@ -138,8 +139,8 @@
final String id3 = "3";
final Item item3 = generateFakeImageItem(id3);
final String id4 = "4";
- final Item item4SameDateTakenAsItem3 = ItemTest.generateItem(id4, "image/jpeg",
- item3.getDateTaken(), /* generationModified= */ 1L, /* duration */ 1000);
+ final Item item4SameDateTakenAsItem3 =
+ generateJpegItem(id4, item3.getDateTaken(), /* generationModified */ 1L);
mSelection.addSelectedItem(item1);
mSelection.addSelectedItem(item2);
@@ -290,7 +291,6 @@
final long dateTakenMs = System.currentTimeMillis() + Long.parseLong(id)
* DateUtils.DAY_IN_MILLIS;
- return ItemTest.generateItem(id, "image/jpeg", dateTakenMs,
- /* generationModified= */ 1L, /* duration= */ 1000L);
+ return generateJpegItem(id, dateTakenMs, /* generationModified */ 1L);
}
}
\ No newline at end of file
diff --git a/tests/src/com/android/providers/media/photopicker/data/model/ItemTest.java b/tests/src/com/android/providers/media/photopicker/data/model/ItemTest.java
index a78bbef..6ff2c3d 100644
--- a/tests/src/com/android/providers/media/photopicker/data/model/ItemTest.java
+++ b/tests/src/com/android/providers/media/photopicker/data/model/ItemTest.java
@@ -22,6 +22,10 @@
import static android.provider.MediaStore.Files.FileColumns._SPECIAL_FORMAT_MOTION_PHOTO;
import static android.provider.MediaStore.Files.FileColumns._SPECIAL_FORMAT_NONE;
+import static com.android.providers.media.photopicker.data.model.ModelTestUtils.generateItem;
+import static com.android.providers.media.photopicker.data.model.ModelTestUtils.generateJpegItem;
+import static com.android.providers.media.photopicker.data.model.ModelTestUtils.generateSpecialFormatItem;
+
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
@@ -29,7 +33,6 @@
import android.database.MatrixCursor;
import android.net.Uri;
import android.os.UserHandle;
-import android.provider.MediaStore;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
@@ -66,7 +69,6 @@
assertThat(item.getContentUri()).isEqualTo(
Uri.parse("content://com.android.providers.media.photopicker/media/1"));
- assertThat(item.isDate()).isFalse();
assertThat(item.isImage()).isTrue();
assertThat(item.isVideo()).isFalse();
assertThat(item.isGifOrAnimatedWebp()).isFalse();
@@ -97,7 +99,6 @@
assertThat(item.isImage()).isTrue();
- assertThat(item.isDate()).isFalse();
assertThat(item.isVideo()).isFalse();
assertThat(item.isGifOrAnimatedWebp()).isFalse();
assertThat(item.isMotionPhoto()).isFalse();
@@ -114,7 +115,6 @@
assertThat(item.isImage()).isTrue();
- assertThat(item.isDate()).isFalse();
assertThat(item.isVideo()).isFalse();
assertThat(item.isGifOrAnimatedWebp()).isFalse();
assertThat(item.isMotionPhoto()).isFalse();
@@ -131,7 +131,6 @@
assertThat(item.isVideo()).isTrue();
- assertThat(item.isDate()).isFalse();
assertThat(item.isImage()).isFalse();
assertThat(item.isGifOrAnimatedWebp()).isFalse();
assertThat(item.isMotionPhoto()).isFalse();
@@ -151,7 +150,6 @@
assertThat(item.isImage()).isTrue();
assertThat(item.isGifOrAnimatedWebp()).isFalse();
- assertThat(item.isDate()).isFalse();
assertThat(item.isVideo()).isFalse();
}
@@ -170,7 +168,6 @@
assertThat(gifItem.isImage()).isTrue();
assertThat(gifItem.isAnimatedWebp()).isFalse();
- assertThat(gifItem.isDate()).isFalse();
assertThat(gifItem.isVideo()).isFalse();
final Item animatedWebpItem = generateSpecialFormatItem(id, mimeType, dateTaken,
@@ -181,7 +178,6 @@
assertThat(animatedWebpItem.isImage()).isTrue();
assertThat(animatedWebpItem.isGif()).isFalse();
- assertThat(animatedWebpItem.isDate()).isFalse();
assertThat(animatedWebpItem.isVideo()).isFalse();
}
@@ -198,22 +194,11 @@
assertThat(item.isImage()).isTrue();
assertThat(item.isGifOrAnimatedWebp()).isFalse();
- assertThat(item.isDate()).isFalse();
assertThat(item.isVideo()).isFalse();
assertThat(item.isMotionPhoto()).isFalse();
}
@Test
- public void testCreateDateItem() {
- final long dateTaken = 12345678L;
-
- final Item item = Item.createDateItem(dateTaken);
-
- assertThat(item.getDateTaken()).isEqualTo(dateTaken);
- assertThat(item.isDate()).isTrue();
- }
-
- @Test
public void testCompareTo_differentDateTaken() {
final String id1 = "1";
final long dateTaken1 = 1000000L;
@@ -330,44 +315,4 @@
PickerSyncController.LOCAL_PICKER_PROVIDER_AUTHORITY});
return cursor;
}
-
- private static Item generateJpegItem(String id, long dateTaken, long generationModified) {
- final String mimeType = "image/jpeg";
- final long duration = 1000;
- return generateItem(id, mimeType, dateTaken, generationModified, duration);
- }
-
- /**
- * Generate the {@link Item}
- * @param id the id
- * @param mimeType the mime type
- * @param dateTaken the time of date taken
- * @param generationModified the generation number associated with the media
- * @param duration the duration
- * @return the Item
- */
- public static Item generateItem(String id, String mimeType, long dateTaken,
- long generationModified, long duration) {
- return new Item(id, mimeType, dateTaken, generationModified, duration,
- MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL, Long.parseLong(id)),
- _SPECIAL_FORMAT_NONE);
- }
-
- /**
- * Generate the {@link Item}
- * @param id the id
- * @param mimeType the mime type
- * @param dateTaken the time of date taken
- * @param generationModified the generation number associated with the media
- * @param duration the duration
- * @param specialFormat the special format. See
- * {@link MediaStore.Files.FileColumns#_SPECIAL_FORMAT}
- * @return the Item
- */
- public static Item generateSpecialFormatItem(String id, String mimeType, long dateTaken,
- long generationModified, long duration, int specialFormat) {
- return new Item(id, mimeType, dateTaken, generationModified, duration,
- MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL, Long.parseLong(id)),
- specialFormat);
- }
}
diff --git a/tests/src/com/android/providers/media/photopicker/data/model/ModelTestUtils.java b/tests/src/com/android/providers/media/photopicker/data/model/ModelTestUtils.java
new file mode 100644
index 0000000..da40e4d
--- /dev/null
+++ b/tests/src/com/android/providers/media/photopicker/data/model/ModelTestUtils.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.media.photopicker.data.model;
+
+import static android.provider.MediaStore.Files.FileColumns._SPECIAL_FORMAT_NONE;
+
+import android.provider.MediaStore;
+
+public class ModelTestUtils {
+ private static final String MIME_TYPE_JPEG = "image/jpeg";
+
+ /**
+ * Generate the {@link Item}
+ * @param id the id
+ * @param mimeType the mime type
+ * @param dateTaken the time of date taken
+ * @param generationModified the generation number associated with the media
+ * @param duration the duration
+ * @return the Item
+ */
+ public static Item generateItem(String id, String mimeType, long dateTaken,
+ long generationModified, long duration) {
+ return new Item(id, mimeType, dateTaken, generationModified, duration,
+ MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL, Long.parseLong(id)),
+ _SPECIAL_FORMAT_NONE);
+ }
+
+ /**
+ * Generate the {@link Item}
+ * @param id the id
+ * @param mimeType the mime type
+ * @param dateTaken the time of date taken
+ * @param generationModified the generation number associated with the media
+ * @param duration the duration
+ * @param specialFormat the special format. See
+ * {@link MediaStore.Files.FileColumns#_SPECIAL_FORMAT}
+ * @return the Item
+ */
+ public static Item generateSpecialFormatItem(String id, String mimeType, long dateTaken,
+ long generationModified, long duration, int specialFormat) {
+ return new Item(id, mimeType, dateTaken, generationModified, duration,
+ MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL, Long.parseLong(id)),
+ specialFormat);
+ }
+
+ /** Generate the JPEG {@link Item} */
+ public static Item generateJpegItem(String id, long dateTaken, long generationModified) {
+ return generateItem(id, MIME_TYPE_JPEG, dateTaken, generationModified, /* duration */ 1000);
+ }
+}
diff --git a/tests/src/com/android/providers/media/photopicker/ui/PhotosTabAdapterTest.java b/tests/src/com/android/providers/media/photopicker/ui/PhotosTabAdapterTest.java
new file mode 100644
index 0000000..4232563
--- /dev/null
+++ b/tests/src/com/android/providers/media/photopicker/ui/PhotosTabAdapterTest.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.media.photopicker.ui;
+
+import static com.android.providers.media.photopicker.data.model.ModelTestUtils.generateJpegItem;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+
+import android.text.format.DateUtils;
+import android.view.View;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.providers.media.photopicker.data.Selection;
+import com.android.providers.media.photopicker.data.model.Item;
+import com.android.providers.media.photopicker.ui.PhotosTabAdapter.DateHeader;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Tests {@link PhotosTabAdapter}. */
+@RunWith(AndroidJUnit4.class)
+public class PhotosTabAdapterTest {
+ @Test
+ public void test_hasRecentItem() {
+ final PhotosTabAdapter adapter = createAdapter(/* shouldShowRecentSection */ true);
+
+ final List<Item> mediaItems = generateFakeImageItemList(1);
+ final Item mediaItem = mediaItems.get(0);
+
+ adapter.setMediaItems(mediaItems);
+
+ // One media item + "Recent" section header
+ assertThat(adapter.getItemCount()).isEqualTo(2);
+
+ // Check the first adapter item is the "Recent" section header
+ final Object firstAdapterItem = adapter.getAdapterItem(0);
+ assertThat(firstAdapterItem).isInstanceOf(DateHeader.class);
+ assertThat(((DateHeader) firstAdapterItem).timestamp)
+ .isEqualTo(DateHeader.RECENT);
+
+ // Check the second adapter item is our only media item
+ final Object secondAdapterItem = adapter.getAdapterItem(1);
+ assertThat(secondAdapterItem).isInstanceOf(Item.class);
+ assertThat(((Item) secondAdapterItem).getId())
+ .isEqualTo(mediaItem.getId());
+ }
+
+ @Test
+ public void test_exceedMinCount_notSameDay_hasRecentItemAndOneDateItem() {
+ final PhotosTabAdapter adapter = createAdapter(/* shouldShowRecentSection */ true);
+
+ final int mediaItemCount = 13;
+ final List<Item> mediaItems = generateFakeImageItemList(mediaItemCount);
+
+ adapter.setMediaItems(mediaItems);
+
+ // Media items count + "Recent" section header + one other date section header
+ assertThat(adapter.getItemCount()).isEqualTo(mediaItemCount + 2);
+
+ Object adapterItem = adapter.getAdapterItem(0);
+ assertThat(adapterItem).isInstanceOf(DateHeader.class);
+ assertThat(((DateHeader) adapterItem).timestamp)
+ .isEqualTo(DateHeader.RECENT);
+
+ // The index 13 is the next date header because the minimum item count in the "Recent"
+ // section is 12
+ adapterItem = adapter.getAdapterItem(13);
+ assertThat(adapterItem).isInstanceOf(DateHeader.class);
+ assertThat(((DateHeader) adapterItem).timestamp)
+ .isNotEqualTo(DateHeader.RECENT);
+ }
+
+ /**
+ * Test that The total number in `Recent` may exceed the minimum count. If the photo items are
+ * taken on same day, they should not be split apart.
+ */
+ @Test
+ public void test_exceedMinCount_sameDay_hasRecentItemNoDateItem() {
+ final PhotosTabAdapter adapter = createAdapter(/* shouldShowRecentSection */ true);
+
+ final List<Item> mediaItems = generateFakeImageItemList(12);
+
+ // "Manually" generate one more media item
+ final long dateTakenMs = mediaItems.get(mediaItems.size() - 1).getDateTaken();
+ final String lastItemId = "13";
+ final Item lastItem = generateJpegItem(lastItemId, dateTakenMs, /* generationModified */ 1);
+ mediaItems.add(lastItem);
+
+ final int mediaItemsCount = mediaItems.size();
+ adapter.setMediaItems(mediaItems);
+
+ // Media items count + "Recent" section header
+ assertThat(adapter.getItemCount()).isEqualTo(mediaItemsCount + 1);
+
+ // Check the first item is the "Recent" section header
+ final Object firstAdapterItem = adapter.getAdapterItem(0);
+ assertThat(firstAdapterItem).isInstanceOf(DateHeader.class);
+ assertThat(((DateHeader) firstAdapterItem).timestamp)
+ .isEqualTo(DateHeader.RECENT);
+ }
+
+ @Test
+ public void test_noRecentSection() throws Exception {
+ final PhotosTabAdapter adapter = createAdapter(/* shouldShowRecentSection */ false);
+
+ final int mediaItemCount = 3;
+ final List<Item> mediaItems = generateFakeImageItemList(mediaItemCount);
+
+ adapter.setMediaItems(mediaItems);
+
+ // Media items count + date section headers (1 item per section)
+ assertThat(adapter.getItemCount()).isEqualTo(2 * mediaItemCount);
+
+ // Test the 1st item is a date header
+ final Object firstDateHeader = adapter.getAdapterItem(0);
+ assertThat(firstDateHeader).isInstanceOf(DateHeader.class);
+ assertThat(((DateHeader) firstDateHeader).timestamp)
+ .isNotEqualTo(DateHeader.RECENT);
+
+ // Test the 3rd item is a date header, and the timestamp is greater than the previous one.
+ final Object secondDateHeader = adapter.getAdapterItem(2);
+ assertThat(secondDateHeader).isInstanceOf(DateHeader.class);
+ assertThat(((DateHeader) secondDateHeader).timestamp)
+ .isGreaterThan(((DateHeader) firstDateHeader).timestamp);
+
+ // Test the 5th item is a date header, and the timestamp is greater than the previous one.
+ final Object thirdDateHeader = adapter.getAdapterItem(4);
+ assertThat(thirdDateHeader).isInstanceOf(DateHeader.class);
+ assertThat(((DateHeader) thirdDateHeader).timestamp)
+ .isGreaterThan(((DateHeader) secondDateHeader).timestamp);
+ }
+
+ @Test
+ public void testGetCategoryItems_dataIsUpdated() {
+ final PhotosTabAdapter adapter = createAdapter(/* shouldShowRecentSection */ false);
+
+ final int mediaItemCount = 3;
+ final List<Item> mediaItems = generateFakeImageItemList(mediaItemCount);
+
+ adapter.setMediaItems(mediaItems);
+
+ // Media items count + date section headers (1 item per section)
+ assertThat(adapter.getItemCount()).isEqualTo(2 * mediaItemCount);
+
+ // "Update" media collection
+ final int newMediaItemCount = 5;
+ final List<Item> newMediaItems = generateFakeImageItemList(newMediaItemCount);
+
+ adapter.setMediaItems(newMediaItems);
+
+ // Media items count + date section headers (1 item per section)
+ assertThat(adapter.getItemCount()).isEqualTo(2 * newMediaItemCount);
+ }
+
+ private static PhotosTabAdapter createAdapter(boolean shouldShowRecentSection) {
+ return new PhotosTabAdapter(/* showRecentSection */ shouldShowRecentSection,
+ mock(Selection.class), mock(ImageLoader.class), mock(View.OnClickListener.class),
+ mock(View.OnLongClickListener.class));
+ }
+
+ private static Item generateFakeImageItem(String id) {
+ final long dateTakenMs = System.currentTimeMillis()
+ + Long.parseLong(id) * DateUtils.DAY_IN_MILLIS;
+ return generateJpegItem(id, dateTakenMs, /* generationModified */ 1L);
+ }
+
+ private static List<Item> generateFakeImageItemList(int n) {
+ final List<Item> itemList = new ArrayList<>();
+ for (int i = 0; i < n; i++) {
+ itemList.add(generateFakeImageItem(String.valueOf(i)));
+ }
+ return itemList;
+ }
+}
diff --git a/tests/src/com/android/providers/media/photopicker/viewmodel/PickerViewModelTest.java b/tests/src/com/android/providers/media/photopicker/viewmodel/PickerViewModelTest.java
index ab50696..b95bea6 100644
--- a/tests/src/com/android/providers/media/photopicker/viewmodel/PickerViewModelTest.java
+++ b/tests/src/com/android/providers/media/photopicker/viewmodel/PickerViewModelTest.java
@@ -30,13 +30,11 @@
import android.content.Intent;
import android.database.Cursor;
import android.database.MatrixCursor;
-import android.net.Uri;
import android.provider.MediaStore;
import android.text.format.DateUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.lifecycle.LiveData;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
@@ -45,7 +43,7 @@
import com.android.providers.media.photopicker.data.UserIdManager;
import com.android.providers.media.photopicker.data.model.Category;
import com.android.providers.media.photopicker.data.model.Item;
-import com.android.providers.media.photopicker.data.model.ItemTest;
+import com.android.providers.media.photopicker.data.model.ModelTestUtils;
import com.android.providers.media.photopicker.data.model.UserId;
import com.android.providers.media.util.ForegroundThread;
@@ -61,15 +59,9 @@
@RunWith(AndroidJUnit4.class)
public class PickerViewModelTest {
-
- private static final String FAKE_IMAGE_MIME_TYPE = "image/jpg";
private static final String FAKE_CATEGORY_NAME = "testCategoryName";
private static final String FAKE_ID = "5";
- private static final Category FAKE_CATEGORY =
- new Category(FAKE_ID, PickerSyncController.LOCAL_PICKER_PROVIDER_AUTHORITY,
- FAKE_CATEGORY_NAME, Uri.parse("content://media/foo"), 0, true);
-
@Rule
public InstantTaskExecutorRule instantTaskExecutorRule = new InstantTaskExecutorRule();
@@ -96,7 +88,7 @@
}
@Test
- public void testGetItems_noItems() throws Exception {
+ public void testGetItems_noItems() {
final int itemCount = 0;
mItemsProvider.setItems(generateFakeImageItemList(itemCount));
mPickerViewModel.updateItems();
@@ -111,141 +103,6 @@
}
@Test
- public void testGetItems_hasRecentItem() throws Exception {
- final int itemCount = 1;
- final List<Item> fakeItemList = generateFakeImageItemList(itemCount);
- final Item fakeItem = fakeItemList.get(0);
- mItemsProvider.setItems(generateFakeImageItemList(itemCount));
- mPickerViewModel.updateItems();
- // We use ForegroundThread to execute the loadItems in updateItems(), wait for the thread
- // idle
- ForegroundThread.waitForIdle();
-
- final List<Item> itemList = mPickerViewModel.getItems().getValue();
-
- // Original one item + 1 Recent item
- assertThat(itemList.size()).isEqualTo(itemCount + 1);
- // Check the first item is recent item
- final Item recentItem = itemList.get(0);
- assertThat(recentItem.isDate()).isTrue();
- assertThat(recentItem.getDateTaken()).isEqualTo(0);
- // Check the second item is fakeItem
- final Item firstPhotoItem = itemList.get(1);
- assertThat(firstPhotoItem.getId()).isEqualTo(fakeItem.getId());
- }
-
- @Test
- public void testGetItems_exceedMinCount_notSameDay_hasRecentItemAndOneDateItem()
- throws Exception {
- final int itemCount = 13;
- mItemsProvider.setItems(generateFakeImageItemList(itemCount));
- mPickerViewModel.updateItems();
- // We use ForegroundThread to execute the loadItems in updateItems(), wait for the thread
- // idle
- ForegroundThread.waitForIdle();
-
- final List<Item> itemList = mPickerViewModel.getItems().getValue();
-
- // Original item count + 1 Recent item + 1 date item
- assertThat(itemList.size()).isEqualTo(itemCount + 2);
- assertThat(itemList.get(0).isDate()).isTrue();
- assertThat(itemList.get(0).getDateTaken()).isEqualTo(0);
- // The index 13 is the next date header because the minimum item count in recent section is
- // 12
- assertThat(itemList.get(13).isDate()).isTrue();
- assertThat(itemList.get(13).getDateTaken()).isNotEqualTo(0);
- }
-
- /**
- * Test that The total number in `Recent` may exceed the minimum count. If the photo items are
- * taken on same day, they should not be split apart.
- */
- @Test
- public void testGetItems_exceedMinCount_sameDay_hasRecentItemNoDateItem() throws Exception {
- final int originalItemCount = 12;
- final String lastItemId = "13";
- final List<Item> fakeItemList = generateFakeImageItemList(originalItemCount);
- final long dateTakenMs = fakeItemList.get(originalItemCount - 1).getDateTaken();
- final long generationModified = 1L;
- final Item lastItem = ItemTest.generateItem(lastItemId, FAKE_IMAGE_MIME_TYPE,
- dateTakenMs, generationModified, /* duration= */ 1000L);
- fakeItemList.add(lastItem);
- final int itemCount = fakeItemList.size();
- mItemsProvider.setItems(fakeItemList);
- mPickerViewModel.updateItems();
- // We use ForegroundThread to execute the loadItems in updateItems(), wait for the thread
- // idle
- ForegroundThread.waitForIdle();
-
- final List<Item> itemList = mPickerViewModel.getItems().getValue();
-
- // Original item count + 1 new Recent item
- assertThat(itemList.size()).isEqualTo(itemCount + 1);
- assertThat(itemList.get(0).isDate()).isTrue();
- assertThat(itemList.get(0).getDateTaken()).isEqualTo(0);
- }
-
- @Test
- public void testGetCategoryItems() throws Exception {
- final int itemCount = 3;
- final LiveData<List<Item>> categoryItems = mPickerViewModel.getCategoryItems(FAKE_CATEGORY);
- mItemsProvider.setItems(generateFakeImageItemList(itemCount));
- mPickerViewModel.updateCategoryItems();
- // We use ForegroundThread to execute the loadItems in updateCategoryItems(), wait for the
- // thread idle
- ForegroundThread.waitForIdle();
-
- final List<Item> itemList = categoryItems.getValue();
-
- // Original item count + 3 date items
- assertThat(itemList.size()).isEqualTo(itemCount + 3);
- // Test the first item is date item
- final Item firstDateItem = itemList.get(0);
- assertThat(firstDateItem.isDate()).isTrue();
- assertThat(firstDateItem.getDateTaken()).isNotEqualTo(0);
- // Test the third item is date item and the dateTaken is larger than previous date item
- final Item secondDateItem = itemList.get(2);
- assertThat(secondDateItem.isDate()).isTrue();
- assertThat(secondDateItem.getDateTaken()).isGreaterThan(firstDateItem.getDateTaken());
- // Test the fifth item is date item and the dateTaken is larger than previous date item
- final Item thirdDateItem = itemList.get(4);
- assertThat(thirdDateItem.isDate()).isTrue();
- assertThat(thirdDateItem.getDateTaken()).isGreaterThan(secondDateItem.getDateTaken());
- }
-
- @Test
- public void testGetCategoryItems_dataIsUpdated() throws Exception {
- final int itemCount = 3;
- final LiveData<List<Item>> categoryItems = mPickerViewModel.getCategoryItems(FAKE_CATEGORY);
- mItemsProvider.setItems(generateFakeImageItemList(itemCount));
- mPickerViewModel.updateCategoryItems();
- // We use ForegroundThread to execute the loadItems in updateCategoryItems(), wait for the
- // thread idle
- ForegroundThread.waitForIdle();
-
- final List<Item> itemList = categoryItems.getValue();
-
- // Original item count + 3 date items
- assertThat(itemList.size()).isEqualTo(itemCount + 3);
-
- final int updatedItemCount = 5;
- mItemsProvider.setItems(generateFakeImageItemList(updatedItemCount));
-
- // trigger updateCategoryItems and wait the idle
- mPickerViewModel.updateCategoryItems();
-
- // We use ForegroundThread to execute the loadItems in updateCategoryItems(), wait for the
- // thread idle
- ForegroundThread.waitForIdle();
-
- // Get the result again to check the result is as expected
- final List<Item> updatedItemList = categoryItems.getValue();
-
- // Original item count + 5 date items
- assertThat(updatedItemList.size()).isEqualTo(updatedItemCount + 5);
- }
-
- @Test
public void testGetCategories() throws Exception {
final Context context = InstrumentationRegistry.getTargetContext();
final int categoryCount = 2;
@@ -281,14 +138,10 @@
}
}
-
private static Item generateFakeImageItem(String id) {
- final long dateTakenMs = System.currentTimeMillis() + Long.parseLong(id)
- * DateUtils.DAY_IN_MILLIS;
- final long generationModified = 1L;
-
- return ItemTest.generateItem(id, FAKE_IMAGE_MIME_TYPE, dateTakenMs, generationModified,
- /* duration= */ 1000L);
+ final long dateTakenMs = System.currentTimeMillis()
+ + Long.parseLong(id) * DateUtils.DAY_IN_MILLIS;
+ return ModelTestUtils.generateJpegItem(id, dateTakenMs, /* generationModified */ 1L);
}
private static List<Item> generateFakeImageItemList(int num) {
diff --git a/tests/src/com/android/providers/media/scan/MediaScannerTest.java b/tests/src/com/android/providers/media/scan/MediaScannerTest.java
index 275c508..6a8c689 100644
--- a/tests/src/com/android/providers/media/scan/MediaScannerTest.java
+++ b/tests/src/com/android/providers/media/scan/MediaScannerTest.java
@@ -123,7 +123,7 @@
}
@Override
- protected void checkConfigAndUpdateGetContentAlias() {
+ protected void storageNativeBootPropertyChangeListener() {
// Ignore this as test app cannot read device config
}
diff --git a/tests/src/com/android/providers/media/stableuris/job/StableUriIdleMaintenanceServiceTest.java b/tests/src/com/android/providers/media/stableuris/job/StableUriIdleMaintenanceServiceTest.java
new file mode 100644
index 0000000..449a036
--- /dev/null
+++ b/tests/src/com/android/providers/media/stableuris/job/StableUriIdleMaintenanceServiceTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.media.stableuris.job;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.Manifest;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.Cursor;
+import android.provider.DeviceConfig;
+import android.provider.MediaStore;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.providers.media.ConfigStore;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@RunWith(AndroidJUnit4.class)
+public class StableUriIdleMaintenanceServiceTest {
+ private static final String TAG = "StableUriIdleMaintenanceServiceTest";
+
+ private boolean mInitialDeviceConfigValue = false;
+
+ @Before
+ public void setUp() throws IOException {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .adoptShellPermissionIdentity(android.Manifest.permission.LOG_COMPAT_CHANGE,
+ android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG,
+ android.Manifest.permission.READ_DEVICE_CONFIG,
+ android.Manifest.permission.WRITE_DEVICE_CONFIG,
+ Manifest.permission.WRITE_MEDIA_STORAGE);
+ // Read existing value of the flag
+ mInitialDeviceConfigValue = Boolean.parseBoolean(
+ DeviceConfig.getProperty(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ ConfigStore.ConfigStoreImpl.KEY_STABILISE_VOLUME_INTERNAL));
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ ConfigStore.ConfigStoreImpl.KEY_STABILISE_VOLUME_INTERNAL, Boolean.TRUE.toString(),
+ false);
+ }
+
+ @After
+ public void tearDown() throws IOException {
+ // Restore previous value of the flag
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ ConfigStore.ConfigStoreImpl.KEY_STABILISE_VOLUME_INTERNAL,
+ String.valueOf(mInitialDeviceConfigValue), false);
+ InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation().dropShellPermissionIdentity();
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 31, codeName = "S")
+ public void testDataMigrationForInternalVolume() {
+ final Context context = InstrumentationRegistry.getTargetContext();
+ final ContentResolver resolver = context.getContentResolver();
+ Set<String> internalFiles = new HashSet<>();
+ MediaStore.waitForIdle(resolver);
+ try (Cursor c = resolver.query(MediaStore.Files.getContentUri(MediaStore.VOLUME_INTERNAL),
+ new String[]{MediaStore.Files.FileColumns.DATA}, null, null)) {
+ assertNotNull(c);
+ while (c.moveToNext()) {
+ String path = c.getString(0);
+ internalFiles.add(path);
+ }
+ }
+ assertFalse(internalFiles.isEmpty());
+ // Delete any existing backup to confirm that backup created is by idle maintenance job
+ MediaStore.deleteBackedUpFilePaths(resolver, MediaStore.VOLUME_INTERNAL);
+
+ MediaStore.waitForIdle(resolver);
+ // Creates backup
+ MediaStore.runIdleMaintenanceForStableUris(resolver);
+
+ // Read all backed up paths
+ List<String> backedUpPaths = Arrays.asList(
+ MediaStore.readBackedUpFilePaths(resolver, MediaStore.VOLUME_INTERNAL));
+ Log.i(TAG, "BackedUpPaths count:" + backedUpPaths.size());
+ // Verify that all internal files are backed up
+ for (String path : internalFiles) {
+ assertTrue(backedUpPaths.contains(path));
+ }
+ }
+}