[automerger skipped] Import translations. DO NOT MERGE ANYWHERE am: d0aa80b610 -s ours
am skip reason: subject contains skip directive
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/providers/MediaProvider/+/15210586
Change-Id: Id56a57d75bd1570b596827951436ba90b76084ac
diff --git a/Android.bp b/Android.bp
index f1c92d5..3cad281 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,4 +1,21 @@
+package {
+ default_applicable_licenses: ["packages_providers_MediaProvider_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+ name: "packages_providers_MediaProvider_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
android_app {
name: "MediaProvider",
manifest: "AndroidManifest.xml",
@@ -7,13 +24,15 @@
"androidx.appcompat_appcompat",
"androidx.core_core",
"guava",
+ "modules-utils-build",
],
libs: [
"unsupportedappusage",
"app-compat-annotations",
+ "framework-annotations-lib",
"framework-mediaprovider.impl",
- "framework_mediaprovider_annotation",
+ "framework-media.stubs.module_lib",
"framework-statsd",
],
@@ -40,6 +59,7 @@
sdk_version: "module_current",
min_sdk_version: "30",
+ target_sdk_version: "30",
certificate: "media",
privileged: true,
@@ -57,6 +77,8 @@
"-Xep:MediaProviderMimeType:ERROR",
],
},
+
+ required: ["preinstalled-packages-com.android.providers.media.module.xml"],
}
// Used by MediaProvider and MediaProviderTests
@@ -96,6 +118,15 @@
genrule {
name: "statslog-mediaprovider-java-gen",
tools: ["stats-log-api-gen"],
- cmd: "$(location stats-log-api-gen) --java $(out) --module mediaprovider --javaPackage com.android.providers.media --javaClass MediaProviderStatsLog",
+ cmd: "$(location stats-log-api-gen) --java $(out) --module mediaprovider" +
+ " --javaPackage com.android.providers.media --javaClass MediaProviderStatsLog" +
+ " --minApiLevel 30",
out: ["com/android/providers/media/MediaProviderStatsLog.java"],
}
+
+prebuilt_etc {
+ name: "preinstalled-packages-com.android.providers.media.module.xml",
+ src: "preinstalled-packages-com.android.providers.media.module.xml",
+ sub_dir: "sysconfig",
+}
+
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 4fe4843..d57a013 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -8,6 +8,8 @@
<uses-permission android:name="android.permission.MANAGE_USERS" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+ <!-- Permission required to prompt for the work profile to be turned on -->
+ <uses-permission android:name="android.permission.MODIFY_QUIET_MODE" />
<uses-permission android:name="android.permission.WATCH_APPOPS" />
<uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
@@ -25,9 +27,17 @@
<uses-permission android:name="android.permission.LOG_COMPAT_CHANGE"/>
<uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"/>
+ <!-- Permissions required for reading device configs -->
+ <uses-permission android:name="android.permission.READ_DEVICE_CONFIG"/>
+
+ <uses-permission android:name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND"/>
+
<!-- Permissions required for statsd pull metrics -->
<uses-permission android:name="android.permission.REGISTER_STATS_PULL_ATOM"/>
+ <!-- Permissions required to check if an app is in the foreground or not during IO -->
+ <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
+
<application
android:name="com.android.providers.media.MediaApplication"
android:label="@string/app_label"
@@ -55,7 +65,8 @@
</provider>
<!-- Handles database upgrades after OTAs, then disables itself -->
- <receiver android:name="com.android.providers.media.MediaUpgradeReceiver">
+ <receiver android:name="com.android.providers.media.MediaUpgradeReceiver"
+ android:exported="true">
<!-- This broadcast is sent after the core system has finished
booting, before the home app is launched or BOOT_COMPLETED
is sent. -->
@@ -64,7 +75,8 @@
</intent-filter>
</receiver>
- <receiver android:name="com.android.providers.media.MediaReceiver">
+ <receiver android:name="com.android.providers.media.MediaReceiver"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
@@ -77,10 +89,6 @@
<data android:scheme="package" />
</intent-filter>
<intent-filter>
- <action android:name="android.intent.action.MEDIA_MOUNTED" />
- <data android:scheme="file" />
- </intent-filter>
- <intent-filter>
<action android:name="android.intent.action.MEDIA_SCANNER_SCAN_FILE" />
<data android:scheme="file" />
</intent-filter>
@@ -97,6 +105,7 @@
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">
<intent-filter>
<action android:name="android.service.storage.ExternalStorageService" />
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/OWNERS b/OWNERS
index 4e37503..ed4dc2a 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,7 +1 @@
-jsharkey@android.com
-maco@google.com
-marcone@google.com
-nandana@google.com
-zezeozue@google.com
-corinac@google.com
-sahanas@google.com
\ No newline at end of file
+include platform/frameworks/base:/core/java/android/os/storage/OWNERS
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index c8dbf77..5b80e36 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -3,3 +3,6 @@
[Builtin Hooks Options]
clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
+
+[Hook Scripts]
+hidden_api_txt_checksorted_hook = ${REPO_ROOT}/tools/platform-compat/hiddenapi/checksorted_sha.sh ${PREUPLOAD_COMMIT} ${REPO_ROOT}
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 3af81a2..87582bb 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -8,6 +8,9 @@
"options": [
{
"exclude-annotation": "androidx.test.filters.LargeTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
},
@@ -35,11 +38,22 @@
},
{
"name": "fuse_node_test"
+ },
+ {
+ "name": "CtsMediaProviderTranscodeTests"
}
],
"postsubmit": [
{
"name": "MediaProviderClientTests"
+ },
+ {
+ "name": "CtsAppSecurityHostTestCases",
+ "options": [
+ {
+ "include-filter": "android.appsecurity.cts.ExternalStorageHostTest"
+ }
+ ]
}
]
}
diff --git a/apex/Android.bp b/apex/Android.bp
index 801e979..d53560a 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -1,18 +1,31 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "packages_providers_MediaProvider_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["packages_providers_MediaProvider_license"],
+}
+
apex {
name: "com.android.mediaprovider",
defaults: ["com.android.mediaprovider-defaults"],
manifest: "apex_manifest.json",
apps: ["MediaProvider"],
- prebuilts: ["media-provider-platform-compat-config"],
+ compat_configs: ["media-provider-platform-compat-config"],
}
apex_defaults {
name: "com.android.mediaprovider-defaults",
- java_libs: ["framework-mediaprovider"],
+ bootclasspath_fragments: ["com.android.mediaprovider-bootclasspath-fragment"],
+ prebuilts: ["current_sdkinfo"],
key: "com.android.mediaprovider.key",
certificate: ":com.android.mediaprovider.certificate",
file_contexts: ":com.android.mediaprovider-file_contexts",
min_sdk_version: "30",
+ // Indicates that pre-installed version of this apex can be compressed.
+ // Whether it actually will be compressed is controlled on per-device basis.
+ compressible: true,
updatable: true,
}
@@ -26,3 +39,29 @@
name: "com.android.mediaprovider.certificate",
certificate: "com.android.mediaprovider",
}
+
+sdk {
+ name: "mediaprovider-module-sdk",
+ bootclasspath_fragments: ["com.android.mediaprovider-bootclasspath-fragment"],
+}
+
+// Encapsulate the contributions made by the com.android.mediaprovider to the bootclasspath.
+bootclasspath_fragment {
+ name: "com.android.mediaprovider-bootclasspath-fragment",
+ contents: ["framework-mediaprovider"],
+ apex_available: ["com.android.mediaprovider"],
+
+ // The bootclasspath_fragments that provide APIs on which this depends.
+ fragments: [
+ {
+ apex: "com.android.art",
+ module: "art-bootclasspath-fragment",
+ },
+ ],
+
+ // Additional hidden API flag files to override the defaults. This must only be
+ // modified by the Soong or platform compat team.
+ hidden_api: {
+ max_target_o_low_priority: ["hiddenapi/hiddenapi-max-target-o-low-priority.txt"],
+ },
+}
diff --git a/apex/apex_manifest.json b/apex/apex_manifest.json
index 6d8da53..d87ce8d 100644
--- a/apex/apex_manifest.json
+++ b/apex/apex_manifest.json
@@ -1,4 +1,4 @@
{
"name": "com.android.mediaprovider",
- "version": 309999900
+ "version": 309999910
}
diff --git a/apex/framework/Android.bp b/apex/framework/Android.bp
index 14a6cb3..716f818 100644
--- a/apex/framework/Android.bp
+++ b/apex/framework/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "packages_providers_MediaProvider_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["packages_providers_MediaProvider_license"],
+}
+
java_sdk_library {
name: "framework-mediaprovider",
defaults: ["framework-module-defaults"],
@@ -27,7 +36,8 @@
installable: true,
libs: [
- "framework_mediaprovider_annotation",
+ "androidx.annotation_annotation",
+ "framework-media.stubs.module_lib",
"unsupportedappusage",
],
@@ -49,10 +59,3 @@
],
path: "java",
}
-
-java_library {
- name: "framework_mediaprovider_annotation",
- srcs: [":framework-mediaprovider-annotation-sources"],
- installable: false,
- sdk_version: "core_current",
-}
diff --git a/apex/framework/api/current.txt b/apex/framework/api/current.txt
index 52439fb..2e6312c 100644
--- a/apex/framework/api/current.txt
+++ b/apex/framework/api/current.txt
@@ -3,6 +3,7 @@
public final class MediaStore {
ctor public MediaStore();
+ method public static boolean canManageMedia(@NonNull android.content.Context);
method @NonNull public static android.app.PendingIntent createDeleteRequest(@NonNull android.content.ContentResolver, @NonNull java.util.Collection<android.net.Uri>);
method @NonNull public static android.app.PendingIntent createFavoriteRequest(@NonNull android.content.ContentResolver, @NonNull java.util.Collection<android.net.Uri>, boolean);
method @NonNull public static android.app.PendingIntent createTrashRequest(@NonNull android.content.ContentResolver, @NonNull java.util.Collection<android.net.Uri>, boolean);
@@ -12,11 +13,15 @@
method public static long getGeneration(@NonNull android.content.Context, @NonNull String);
method public static android.net.Uri getMediaScannerUri();
method @Nullable public static android.net.Uri getMediaUri(@NonNull android.content.Context, @NonNull android.net.Uri);
+ method @NonNull public static android.os.ParcelFileDescriptor getOriginalMediaFormatFileDescriptor(@NonNull android.content.Context, @NonNull android.os.ParcelFileDescriptor) throws java.io.IOException;
method @NonNull public static java.util.Set<java.lang.String> getRecentExternalVolumeNames(@NonNull android.content.Context);
+ method @Nullable public static android.net.Uri getRedactedUri(@NonNull android.content.ContentResolver, @NonNull android.net.Uri);
+ method @NonNull public static java.util.List<android.net.Uri> getRedactedUri(@NonNull android.content.ContentResolver, @NonNull java.util.List<android.net.Uri>);
method public static boolean getRequireOriginal(@NonNull android.net.Uri);
method @NonNull public static String getVersion(@NonNull android.content.Context);
method @NonNull public static String getVersion(@NonNull android.content.Context, @NonNull String);
method @NonNull public static String getVolumeName(@NonNull android.net.Uri);
+ method public static boolean isCurrentSystemGallery(@NonNull android.content.ContentResolver, int, @NonNull String);
method @Deprecated @NonNull public static android.net.Uri setIncludePending(@NonNull android.net.Uri);
method @NonNull public static android.net.Uri setRequireOriginal(@NonNull android.net.Uri);
field public static final String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE";
@@ -26,15 +31,18 @@
field public static final String ACTION_VIDEO_CAPTURE = "android.media.action.VIDEO_CAPTURE";
field public static final String AUTHORITY = "media";
field @NonNull public static final android.net.Uri AUTHORITY_URI;
+ field public static final String EXTRA_ACCEPT_ORIGINAL_MEDIA_FORMAT = "android.provider.extra.ACCEPT_ORIGINAL_MEDIA_FORMAT";
field public static final String EXTRA_BRIGHTNESS = "android.provider.extra.BRIGHTNESS";
field public static final String EXTRA_DURATION_LIMIT = "android.intent.extra.durationLimit";
field public static final String EXTRA_FINISH_ON_COMPLETION = "android.intent.extra.finishOnCompletion";
field public static final String EXTRA_FULL_SCREEN = "android.intent.extra.fullScreen";
field public static final String EXTRA_MEDIA_ALBUM = "android.intent.extra.album";
field public static final String EXTRA_MEDIA_ARTIST = "android.intent.extra.artist";
+ field public static final String EXTRA_MEDIA_CAPABILITIES = "android.provider.extra.MEDIA_CAPABILITIES";
+ field public static final String EXTRA_MEDIA_CAPABILITIES_UID = "android.provider.extra.MEDIA_CAPABILITIES_UID";
field public static final String EXTRA_MEDIA_FOCUS = "android.intent.extra.focus";
field public static final String EXTRA_MEDIA_GENRE = "android.intent.extra.genre";
- field public static final String EXTRA_MEDIA_PLAYLIST = "android.intent.extra.playlist";
+ field @Deprecated public static final String EXTRA_MEDIA_PLAYLIST = "android.intent.extra.playlist";
field public static final String EXTRA_MEDIA_RADIO_CHANNEL = "android.intent.extra.radio_channel";
field public static final String EXTRA_MEDIA_TITLE = "android.intent.extra.title";
field public static final String EXTRA_OUTPUT = "output";
@@ -58,6 +66,7 @@
field public static final String MEDIA_SCANNER_VOLUME = "volume";
field public static final String META_DATA_REVIEW_GALLERY_PREWARM_SERVICE = "android.media.review_gallery_prewarm_service";
field public static final String META_DATA_STILL_IMAGE_CAMERA_PREWARM_SERVICE = "android.media.still_image_camera_preview_service";
+ field public static final String QUERY_ARG_INCLUDE_RECENTLY_UNMOUNTED_VOLUMES = "android:query-arg-recently-unmounted-volumes";
field public static final String QUERY_ARG_MATCH_FAVORITE = "android:query-arg-match-favorite";
field public static final String QUERY_ARG_MATCH_PENDING = "android:query-arg-match-pending";
field public static final String QUERY_ARG_MATCH_TRASHED = "android:query-arg-match-trashed";
@@ -114,7 +123,7 @@
field public static final android.net.Uri INTERNAL_CONTENT_URI;
}
- public static final class MediaStore.Audio.Artists.Albums implements android.provider.MediaStore.Audio.AlbumColumns {
+ public static final class MediaStore.Audio.Artists.Albums implements android.provider.BaseColumns android.provider.MediaStore.Audio.AlbumColumns {
ctor public MediaStore.Audio.Artists.Albums();
method public static android.net.Uri getContentUri(String, long);
}
@@ -133,6 +142,7 @@
field public static final String IS_MUSIC = "is_music";
field public static final String IS_NOTIFICATION = "is_notification";
field public static final String IS_PODCAST = "is_podcast";
+ field public static final String IS_RECORDING = "is_recording";
field public static final String IS_RINGTONE = "is_ringtone";
field @Deprecated public static final String TITLE_KEY = "title_key";
field public static final String TITLE_RESOURCE_URI = "title_resource_uri";
@@ -178,33 +188,33 @@
field public static final String RECORD_SOUND_ACTION = "android.provider.MediaStore.RECORD_SOUND";
}
- public static final class MediaStore.Audio.Playlists implements android.provider.BaseColumns android.provider.MediaStore.Audio.PlaylistsColumns {
- ctor public MediaStore.Audio.Playlists();
- method public static android.net.Uri getContentUri(String);
- field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/playlist";
- field public static final String DEFAULT_SORT_ORDER = "name";
- field public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/playlist";
- field public static final android.net.Uri EXTERNAL_CONTENT_URI;
- field public static final android.net.Uri INTERNAL_CONTENT_URI;
+ @Deprecated public static final class MediaStore.Audio.Playlists implements android.provider.BaseColumns android.provider.MediaStore.Audio.PlaylistsColumns {
+ ctor @Deprecated public MediaStore.Audio.Playlists();
+ method @Deprecated public static android.net.Uri getContentUri(String);
+ field @Deprecated public static final String CONTENT_TYPE = "vnd.android.cursor.dir/playlist";
+ field @Deprecated public static final String DEFAULT_SORT_ORDER = "name";
+ field @Deprecated public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/playlist";
+ field @Deprecated public static final android.net.Uri EXTERNAL_CONTENT_URI;
+ field @Deprecated public static final android.net.Uri INTERNAL_CONTENT_URI;
}
- public static final class MediaStore.Audio.Playlists.Members implements android.provider.MediaStore.Audio.AudioColumns {
- ctor public MediaStore.Audio.Playlists.Members();
- method public static android.net.Uri getContentUri(String, long);
- method public static boolean moveItem(android.content.ContentResolver, long, int, int);
- field public static final String AUDIO_ID = "audio_id";
- field public static final String CONTENT_DIRECTORY = "members";
- field public static final String DEFAULT_SORT_ORDER = "play_order";
- field public static final String PLAYLIST_ID = "playlist_id";
- field public static final String PLAY_ORDER = "play_order";
- field public static final String _ID = "_id";
+ @Deprecated public static final class MediaStore.Audio.Playlists.Members implements android.provider.MediaStore.Audio.AudioColumns {
+ ctor @Deprecated public MediaStore.Audio.Playlists.Members();
+ method @Deprecated public static android.net.Uri getContentUri(String, long);
+ method @Deprecated public static boolean moveItem(android.content.ContentResolver, long, int, int);
+ field @Deprecated public static final String AUDIO_ID = "audio_id";
+ field @Deprecated public static final String CONTENT_DIRECTORY = "members";
+ field @Deprecated public static final String DEFAULT_SORT_ORDER = "play_order";
+ field @Deprecated public static final String PLAYLIST_ID = "playlist_id";
+ field @Deprecated public static final String PLAY_ORDER = "play_order";
+ field @Deprecated public static final String _ID = "_id";
}
- public static interface MediaStore.Audio.PlaylistsColumns extends android.provider.MediaStore.MediaColumns {
+ @Deprecated public static interface MediaStore.Audio.PlaylistsColumns extends android.provider.MediaStore.MediaColumns {
field @Deprecated public static final String DATA = "_data";
- field public static final String DATE_ADDED = "date_added";
- field public static final String DATE_MODIFIED = "date_modified";
- field public static final String NAME = "name";
+ field @Deprecated public static final String DATE_ADDED = "date_added";
+ field @Deprecated public static final String DATE_MODIFIED = "date_modified";
+ field @Deprecated public static final String NAME = "name";
}
public static final class MediaStore.Audio.Radio {
@@ -236,7 +246,7 @@
field public static final int MEDIA_TYPE_DOCUMENT = 6; // 0x6
field public static final int MEDIA_TYPE_IMAGE = 1; // 0x1
field public static final int MEDIA_TYPE_NONE = 0; // 0x0
- field public static final int MEDIA_TYPE_PLAYLIST = 4; // 0x4
+ field @Deprecated public static final int MEDIA_TYPE_PLAYLIST = 4; // 0x4
field public static final int MEDIA_TYPE_SUBTITLE = 5; // 0x5
field public static final int MEDIA_TYPE_VIDEO = 3; // 0x3
field public static final String MIME_TYPE = "mime_type";
diff --git a/apex/framework/api/system-current.txt b/apex/framework/api/system-current.txt
index 5ce4218..d29a6ed 100644
--- a/apex/framework/api/system-current.txt
+++ b/apex/framework/api/system-current.txt
@@ -8,6 +8,7 @@
method @WorkerThread public static void waitForIdle(@NonNull android.content.ContentResolver);
field public static final String AUTHORITY_LEGACY = "media_legacy";
field @NonNull public static final android.net.Uri AUTHORITY_LEGACY_URI;
+ field public static final String QUERY_ARG_DEFER_SCAN = "android:query-arg-defer-scan";
}
}
diff --git a/apex/framework/java/android/provider/MediaStore.java b/apex/framework/java/android/provider/MediaStore.java
index e49f338..c39d334 100644
--- a/apex/framework/java/android/provider/MediaStore.java
+++ b/apex/framework/java/android/provider/MediaStore.java
@@ -29,6 +29,7 @@
import android.annotation.SystemApi;
import android.annotation.WorkerThread;
import android.app.Activity;
+import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ClipData;
@@ -39,19 +40,25 @@
import android.content.Context;
import android.content.Intent;
import android.content.UriPermission;
+import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageDecoder;
import android.graphics.PostProcessor;
+import android.media.ApplicationMediaCapabilities;
import android.media.ExifInterface;
import android.media.MediaFormat;
import android.media.MediaMetadataRetriever;
+import android.media.MediaPlayer;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Environment;
import android.os.OperationCanceledException;
+import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
import android.os.RemoteException;
import android.os.storage.StorageManager;
import android.os.storage.StorageVolume;
@@ -61,6 +68,8 @@
import android.util.Log;
import android.util.Size;
+import androidx.annotation.RequiresApi;
+
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -192,6 +201,10 @@
public static final String FINISH_LEGACY_MIGRATION_CALL = "finish_legacy_migration";
/** {@hide} */
+ public static final String GET_ORIGINAL_MEDIA_FORMAT_FILE_DESCRIPTOR_CALL =
+ "get_original_media_format_file_descriptor";
+
+ /** {@hide} */
@Deprecated
public static final String EXTERNAL_STORAGE_PROVIDER_AUTHORITY =
"com.android.externalstorage.documents";
@@ -202,6 +215,13 @@
public static final String GET_MEDIA_URI_CALL = "get_media_uri";
/** {@hide} */
+ public static final String GET_REDACTED_MEDIA_URI_CALL = "get_redacted_media_uri";
+ /** {@hide} */
+ public static final String GET_REDACTED_MEDIA_URI_LIST_CALL = "get_redacted_media_uri_list";
+ /** {@hide} */
+ public static final String EXTRA_URI_LIST = "uri_list";
+
+ /** {@hide} */
public static final String EXTRA_URI = "uri";
/** {@hide} */
public static final String EXTRA_URI_PERMISSIONS = "uriPermissions";
@@ -213,6 +233,16 @@
/** {@hide} */
public static final String EXTRA_RESULT = "result";
+ /** {@hide} */
+ public static final String EXTRA_FILE_DESCRIPTOR = "file_descriptor";
+
+ /** {@hide} */
+ public static final String IS_SYSTEM_GALLERY_CALL = "is_system_gallery";
+ /** {@hide} */
+ public static final String EXTRA_IS_SYSTEM_GALLERY_UID = "is_system_gallery_uid";
+ /** {@hide} */
+ public static final String EXTRA_IS_SYSTEM_GALLERY_RESPONSE = "is_system_gallery_response";
+
/**
* This is for internal use by the media scanner only.
* Name of the (optional) Uri parameter that determines whether to skip deleting
@@ -331,7 +361,13 @@
public static final String EXTRA_MEDIA_GENRE = "android.intent.extra.genre";
/**
* The name of the Intent-extra used to define the playlist.
+ *
+ * @deprecated Android playlists are now deprecated. We will keep the current
+ * functionality for compatibility resons, but we will no longer take feature
+ * request. We do not advise adding new usages of Android Playlists. M3U files can
+ * be used as an alternative.
*/
+ @Deprecated
public static final String EXTRA_MEDIA_PLAYLIST = "android.intent.extra.playlist";
/**
* The name of the Intent-extra used to define the radio channel.
@@ -446,13 +482,17 @@
* supply the uri through the EXTRA_OUTPUT field for compatibility with old applications.
* If you don't set a ClipData, it will be copied there for you when calling
* {@link Context#startActivity(Intent)}.
- *
- * <p>Note: if you app targets {@link android.os.Build.VERSION_CODES#M M} and above
+ * <p>
+ * Regardless of whether or not EXTRA_OUTPUT is present, when an image is captured via this
+ * intent, {@link android.hardware.Camera#ACTION_NEW_PICTURE} won't be broadcasted.
+ * <p>
+ * Note: if you app targets {@link android.os.Build.VERSION_CODES#M M} and above
* and declares as using the {@link android.Manifest.permission#CAMERA} permission which
* is not granted, then attempting to use this action will result in a {@link
* java.lang.SecurityException}.
*
* @see #EXTRA_OUTPUT
+ * @see android.hardware.Camera#ACTION_NEW_PICTURE
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public final static String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE";
@@ -477,9 +517,13 @@
* supply the uri through the EXTRA_OUTPUT field for compatibility with old applications.
* If you don't set a ClipData, it will be copied there for you when calling
* {@link Context#startActivity(Intent)}.
+ * <p>
+ * Regardless of whether or not EXTRA_OUTPUT is present, when an image is captured via this
+ * intent, {@link android.hardware.Camera#ACTION_NEW_PICTURE} won't be broadcasted.
*
* @see #ACTION_IMAGE_CAPTURE
* @see #EXTRA_OUTPUT
+ * @see android.hardware.Camera#ACTION_NEW_PICTURE
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_IMAGE_CAPTURE_SECURE =
@@ -492,14 +536,20 @@
* The caller may pass in an extra EXTRA_VIDEO_QUALITY to control the video quality.
* <p>
* The caller may pass in an extra EXTRA_OUTPUT to control
- * where the video is written. If EXTRA_OUTPUT is not present the video will be
- * written to the standard location for videos, and the Uri of that location will be
- * returned in the data field of the Uri.
- * As of {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this uri can also be supplied through
- * {@link android.content.Intent#setClipData(ClipData)}. If using this approach, you still must
- * supply the uri through the EXTRA_OUTPUT field for compatibility with old applications.
- * If you don't set a ClipData, it will be copied there for you when calling
- * {@link Context#startActivity(Intent)}.
+ * where the video is written.
+ * <ul>
+ * <li>If EXTRA_OUTPUT is not present, the video will be written to the standard location
+ * for videos, and the Uri of that location will be returned in the data field of the Uri.
+ * {@link android.hardware.Camera#ACTION_NEW_VIDEO} will also be broadcasted when the video
+ * is recorded.
+ * <li>If EXTRA_OUTPUT is assigned a Uri value, no
+ * {@link android.hardware.Camera#ACTION_NEW_VIDEO} will be broadcasted. As of
+ * {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this uri can also be
+ * supplied through {@link android.content.Intent#setClipData(ClipData)}. If using this
+ * approach, you still must supply the uri through the EXTRA_OUTPUT field for compatibility
+ * with old applications. If you don't set a ClipData, it will be copied there for you when
+ * calling {@link Context#startActivity(Intent)}.
+ * </ul>
*
* <p>Note: if you app targets {@link android.os.Build.VERSION_CODES#M M} and above
* and declares as using the {@link android.Manifest.permission#CAMERA} permission which
@@ -510,6 +560,7 @@
* @see #EXTRA_VIDEO_QUALITY
* @see #EXTRA_SIZE_LIMIT
* @see #EXTRA_DURATION_LIMIT
+ * @see android.hardware.Camera#ACTION_NEW_VIDEO
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public final static String ACTION_VIDEO_CAPTURE = "android.media.action.VIDEO_CAPTURE";
@@ -587,6 +638,64 @@
public final static String EXTRA_OUTPUT = "output";
/**
+ * Specify that the caller wants to receive the original media format without transcoding.
+ *
+ * <b>Caution: using this flag can cause app
+ * compatibility issues whenever Android adds support for new media formats.</b>
+ * Clients should instead specify their supported media capabilities explicitly
+ * in their manifest or with the {@link #EXTRA_MEDIA_CAPABILITIES} {@code open} flag.
+ *
+ * This option is useful for apps that don't attempt to parse the actual byte contents of media
+ * files, such as playback using {@link MediaPlayer} or for off-device backup. Note that the
+ * {@link android.Manifest.permission#ACCESS_MEDIA_LOCATION} permission will still be required
+ * to avoid sensitive metadata redaction, similar to {@link #setRequireOriginal(Uri)}.
+ * </ul>
+ *
+ * Note that this flag overrides any explicitly declared {@code media_capabilities.xml} or
+ * {@link ApplicationMediaCapabilities} extras specified in the same {@code open} request.
+ *
+ * <p>This option can be added to the {@code opts} {@link Bundle} in various
+ * {@link ContentResolver} {@code open} methods.
+ *
+ * @see ContentResolver#openTypedAssetFileDescriptor(Uri, String, Bundle)
+ * @see ContentResolver#openTypedAssetFile(Uri, String, Bundle, CancellationSignal)
+ * @see #setRequireOriginal(Uri)
+ * @see MediaStore#getOriginalMediaFormatFileDescriptor(Context, ParcelFileDescriptor)
+ */
+ public final static String EXTRA_ACCEPT_ORIGINAL_MEDIA_FORMAT =
+ "android.provider.extra.ACCEPT_ORIGINAL_MEDIA_FORMAT";
+
+ /**
+ * Specify the {@link ApplicationMediaCapabilities} that should be used while opening a media.
+ *
+ * If the capabilities specified matches the format of the original file, the app will receive
+ * the original file, otherwise, it will get transcoded to a default supported format.
+ *
+ * This flag takes higher precedence over the applications declared
+ * {@code media_capabilities.xml} and is useful for apps that want to have more granular control
+ * over their supported media capabilities.
+ *
+ * <p>This option can be added to the {@code opts} {@link Bundle} in various
+ * {@link ContentResolver} {@code open} methods.
+ *
+ * @see ContentResolver#openTypedAssetFileDescriptor(Uri, String, Bundle)
+ * @see ContentResolver#openTypedAssetFile(Uri, String, Bundle, CancellationSignal)
+ */
+ public final static String EXTRA_MEDIA_CAPABILITIES =
+ "android.provider.extra.MEDIA_CAPABILITIES";
+
+ /**
+ * Specify the UID of the app that should be used to determine supported media capabilities
+ * while opening a media.
+ *
+ * If this specified UID is found to be capable of handling the original media file format, the
+ * app will receive the original file, otherwise, the file will get transcoded to a default
+ * format supported by the specified UID.
+ */
+ public static final String EXTRA_MEDIA_CAPABILITIES_UID =
+ "android.provider.extra.MEDIA_CAPABILITIES_UID";
+
+ /**
* The string that is used when a media attribute is not known. For example,
* if an audio file does not have any meta data, the artist and album columns
* will be set to this value.
@@ -625,11 +734,35 @@
* only be used when {@link ContentResolver#update} operation needs to
* return early without updating metadata for the file. This may make other
* apps see incomplete metadata for the updated file as scan runs
- * asynchronously here. Most apps shouldn't set this flag.
+ * asynchronously here.
+ * Note that when this flag is set, the published file will not appear in
+ * default query until the deferred scan is complete.
+ * Most apps shouldn't set this flag.
*
* @hide
*/
- public static final String QUERY_ARG_DO_ASYNC_SCAN = "android:query-arg-do-async-scan";
+ @SystemApi
+ public static final String QUERY_ARG_DEFER_SCAN = "android:query-arg-defer-scan";
+
+ /**
+ * Flag that requests {@link ContentResolver#query} to include content from
+ * recently unmounted volumes.
+ * <p>
+ * When the flag is set, {@link ContentResolver#query} will return content
+ * from all volumes(i.e., both mounted and recently unmounted volume whose
+ * content is still held by MediaProvider).
+ * <p>
+ * Note that the query result doesn't provide any hint for content from
+ * unmounted volume. It's strongly recommended to use default query to
+ * avoid accessing/operating on the content that are not available on the
+ * device.
+ * <p>
+ * The flag is useful for apps which manage their own database and
+ * query MediaStore in order to synchronize between MediaStore database
+ * and their own database.
+ */
+ public static final String QUERY_ARG_INCLUDE_RECENTLY_UNMOUNTED_VOLUMES =
+ "android:query-arg-recently-unmounted-volumes";
/**
* Specify how {@link MediaColumns#IS_PENDING} items should be filtered when
@@ -775,6 +908,44 @@
}
/**
+ * Returns {@link ParcelFileDescriptor} representing the original media file format for
+ * {@code fileDescriptor}.
+ *
+ * <p>Media files may get transcoded based on an application's media capabilities requirements.
+ * However, in various cases, when the application needs access to the original media file, or
+ * doesn't attempt to parse the actual byte contents of media files, such as playback using
+ * {@link MediaPlayer} or for off-device backup, this method can be useful.
+ *
+ * <p>This method is applicable only for media files managed by {@link MediaStore}.
+ *
+ * <p>The method returns the original file descriptor with the same permission that the caller
+ * has for the input file descriptor.
+ *
+ * @throws IOException if the given {@link ParcelFileDescriptor} could not be converted
+ *
+ * @see MediaStore#EXTRA_ACCEPT_ORIGINAL_MEDIA_FORMAT
+ */
+ public static @NonNull ParcelFileDescriptor getOriginalMediaFormatFileDescriptor(
+ @NonNull Context context,
+ @NonNull ParcelFileDescriptor fileDescriptor) throws IOException {
+ Bundle input = new Bundle();
+ input.putParcelable(EXTRA_FILE_DESCRIPTOR, fileDescriptor);
+ ParcelFileDescriptor pfd;
+ try {
+ Bundle output = context.getContentResolver().call(AUTHORITY,
+ GET_ORIGINAL_MEDIA_FORMAT_FILE_DESCRIPTOR_CALL, null, input);
+ pfd = output.getParcelable(EXTRA_FILE_DESCRIPTOR);
+ } catch (Exception e) {
+ throw new IOException(e);
+ }
+
+ if (pfd == null) {
+ throw new IOException("Input file descriptor already original");
+ }
+ return pfd;
+ }
+
+ /**
* Rewrite the given {@link Uri} to point at
* {@link MediaStore#AUTHORITY_LEGACY}.
*
@@ -1004,26 +1175,23 @@
/**
* Absolute filesystem path to the media item on disk.
* <p>
- * On Android 11, you can use this value when you access an existing
- * file using direct file paths. That's because this value has a valid
- * file path. However, don't assume that the file is always available.
- * Be prepared to handle any file-based I/O errors that could occur.
+ * Apps may use this path to do file operations. However, they should not assume that the
+ * file is always available. Apps must be prepared to handle any file-based I/O errors that
+ * could occur.
* <p>
- * Don't use this value when you create or update a media file, even
- * if you're on Android 11 and are using direct file paths. Instead,
- * use the values of the {@link #DISPLAY_NAME} and
+ * From Android 11 onwards, this column is read-only for apps that target
+ * {@link android.os.Build.VERSION_CODES#R R} and higher. On those devices, when creating or
+ * updating a uri, this column's value is not accepted. Instead, to update the
+ * filesystem location of a file, use the values of the {@link #DISPLAY_NAME} and
* {@link #RELATIVE_PATH} columns.
* <p>
- * Note that apps may not have filesystem permissions to directly access
- * this path. Instead of trying to open this path directly, apps should
- * use {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
- * access.
+ * Though direct file operations are supported,
+ * {@link ContentResolver#openFileDescriptor(Uri, String)} API is recommended for better
+ * performance.
*
- * @deprecated Apps may not have filesystem permissions to directly
- * access this path. Instead of trying to open this path
- * directly, apps should use
- * {@link ContentResolver#openFileDescriptor(Uri, String)}
- * to gain access.
+ * @deprecated Apps that target {@link android.os.Build.VERSION_CODES#R R} and higher
+ * may not update the value of this column. However they may read the file path
+ * value from this column and use in file operations.
*/
@Deprecated
@Column(Cursor.FIELD_TYPE_STRING)
@@ -1609,7 +1777,7 @@
* The MTP storage ID of the file
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@Deprecated
// @Column(Cursor.FIELD_TYPE_INTEGER)
public static final String STORAGE_ID = "storage_id";
@@ -1684,7 +1852,13 @@
/**
* Constant for the {@link #MEDIA_TYPE} column indicating that file
* is a playlist file.
+ *
+ * @deprecated Android playlists are now deprecated. We will keep the current
+ * functionality for compatibility reasons, but we will no longer take
+ * feature request. We do not advise adding new usages of Android Playlists.
+ * M3U files can be used as an alternative.
*/
+ @Deprecated
public static final int MEDIA_TYPE_PLAYLIST = 4;
/**
@@ -1741,6 +1915,68 @@
* @hide
*/
public static final int _MODIFIER_MEDIA_SCAN = 3;
+
+ /**
+ * Constant for the {@link #_MODIFIER} column indicating
+ * that the last modifier of the database row is explicit
+ * {@link ContentResolver} operation and is waiting for metadata
+ * update.
+ * @hide
+ */
+ public static final int _MODIFIER_CR_PENDING_METADATA = 4;
+
+ /**
+ * Status of the transcode file
+ *
+ * For apps that do not support modern media formats for video, we
+ * seamlessly transcode the file and return transcoded file for
+ * both file path and ContentResolver operations. This column tracks
+ * the status of the transcoded file.
+ *
+ * @hide
+ */
+ // @Column(value = Cursor.FIELD_TYPE_INTEGER)
+ public static final String _TRANSCODE_STATUS = "_transcode_status";
+
+ /**
+ * Constant for the {@link #_TRANSCODE_STATUS} column indicating
+ * that the transcode file if exists is empty or never transcoded.
+ * @hide
+ */
+ public static final int TRANSCODE_EMPTY = 0;
+
+ /**
+ * Constant for the {@link #_TRANSCODE_STATUS} column indicating
+ * that the transcode file if exists contains transcoded video.
+ * @hide
+ */
+ public static final int TRANSCODE_COMPLETE = 1;
+
+ /**
+ * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_VIDEO_CODEC_TYPE}
+ * extracted from the video file. This value be null for non-video files.
+ *
+ * @hide
+ */
+ // @Column(value = Cursor.FIELD_TYPE_INTEGER)
+ public static final String _VIDEO_CODEC_TYPE = "_video_codec_type";
+
+ /**
+ * Redacted Uri-ID corresponding to this DB entry. The value will be null if no
+ * redacted uri has ever been created for this uri.
+ *
+ * @hide
+ */
+ // @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
+ public static final String REDACTED_URI_ID = "redacted_uri_id";
+
+ /**
+ * Indexed value of {@link UserIdInt} to which the file belongs.
+ *
+ * @hide
+ */
+ // @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
+ public static final String _USER_ID = "_user_id";
}
}
@@ -2390,21 +2626,13 @@
/**
* Path to the thumbnail file on disk.
- * <p>
- * Note that apps may not have filesystem permissions to directly
- * access this path. Instead of trying to open this path directly,
- * apps should use
- * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
- * access.
*
* As of {@link android.os.Build.VERSION_CODES#Q}, this thumbnail
* has correct rotation, don't need to rotate it again.
*
- * @deprecated Apps may not have filesystem permissions to directly
- * access this path. Instead of trying to open this path
- * directly, apps should use
- * {@link ContentResolver#loadThumbnail}
- * to gain access.
+ * @deprecated Apps that target {@link android.os.Build.VERSION_CODES#R R} and higher
+ * may not update the value of this column. However they may read the file
+ * path value from this column and use in file operations.
*/
@Deprecated
@Column(Cursor.FIELD_TYPE_STRING)
@@ -2581,41 +2809,83 @@
/**
* Non-zero if the audio file is music
+ *
+ * This is mutually exclusive with {@link #IS_ALARM},
+ * {@link #IS_AUDIOBOOK}, {@link #IS_NOTIFICATION},
+ * {@link #IS_PODCAST}, {@link #IS_RECORDING},
+ * and {@link #IS_RINGTONE}.
*/
@Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
public static final String IS_MUSIC = "is_music";
/**
* Non-zero if the audio file is a podcast
+ *
+ * This is mutually exclusive with {@link #IS_ALARM},
+ * {@link #IS_AUDIOBOOK}, {@link #IS_MUSIC},
+ * {@link #IS_NOTIFICATION}, {@link #IS_RECORDING},
+ * and {@link #IS_RINGTONE}.
*/
@Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
public static final String IS_PODCAST = "is_podcast";
/**
* Non-zero if the audio file may be a ringtone
+ *
+ * This is mutually exclusive with {@link #IS_ALARM},
+ * {@link #IS_AUDIOBOOK}, {@link #IS_MUSIC},
+ * {@link #IS_NOTIFICATION}, {@link #IS_PODCAST},
+ * and {@link #IS_RECORDING}.
*/
@Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
public static final String IS_RINGTONE = "is_ringtone";
/**
* Non-zero if the audio file may be an alarm
+ *
+ * This is mutually exclusive with {@link #IS_AUDIOBOOK},
+ * {@link #IS_MUSIC}, {@link #IS_NOTIFICATION},
+ * {@link #IS_PODCAST}, {@link #IS_RECORDING},
+ * and {@link #IS_RINGTONE}.
*/
@Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
public static final String IS_ALARM = "is_alarm";
/**
* Non-zero if the audio file may be a notification sound
+ *
+ * This is mutually exclusive with {@link #IS_ALARM},
+ * {@link #IS_AUDIOBOOK}, {@link #IS_MUSIC},
+ * {@link #IS_PODCAST}, {@link #IS_RECORDING},
+ * and {@link #IS_RINGTONE}.
*/
@Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
public static final String IS_NOTIFICATION = "is_notification";
/**
* Non-zero if the audio file is an audiobook
+ *
+ * This is mutually exclusive with {@link #IS_ALARM},
+ * {@link #IS_MUSIC}, {@link #IS_NOTIFICATION},
+ * {@link #IS_PODCAST}, {@link #IS_RECORDING}, and
+ * {@link #IS_RINGTONE}
*/
@Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
public static final String IS_AUDIOBOOK = "is_audiobook";
/**
+ * Non-zero if the audio file is a voice recording recorded
+ * by voice recorder apps
+ *
+ * This is mutually exclusive with {@link #IS_ALARM},
+ * {@link #IS_AUDIOBOOK}, {@link #IS_MUSIC},
+ * {@link #IS_NOTIFICATION}, {@link #IS_PODCAST},
+ * and {@link #IS_RINGTONE}.
+ */
+ @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
+ public static final String IS_RECORDING = "is_recording";
+
+ /**
* The id of the genre the audio file is from, if any
*/
@Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
@@ -2900,7 +3170,13 @@
/**
* Audio playlist metadata columns.
+ *
+ * @deprecated Android playlists are now deprecated. We will keep the current
+ * functionality for compatibility reasons, but we will no longer take
+ * feature request. We do not advise adding new usages of Android Playlists.
+ * M3U files can be used as an alternative.
*/
+ @Deprecated
public interface PlaylistsColumns extends MediaColumns {
/**
* The name of the playlist
@@ -2910,18 +3186,10 @@
/**
* Path to the playlist file on disk.
- * <p>
- * Note that apps may not have filesystem permissions to directly
- * access this path. Instead of trying to open this path directly,
- * apps should use
- * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
- * access.
*
- * @deprecated Apps may not have filesystem permissions to directly
- * access this path. Instead of trying to open this path
- * directly, apps should use
- * {@link ContentResolver#openFileDescriptor(Uri, String)}
- * to gain access.
+ * @deprecated Apps that target {@link android.os.Build.VERSION_CODES#R R} and higher
+ * may not update the value of this column. However they may read the file
+ * path value from this column and use in file operations.
*/
@Deprecated
@Column(Cursor.FIELD_TYPE_STRING)
@@ -2944,7 +3212,13 @@
/**
* Contains playlists for audio files
+ *
+ * @deprecated Android playlists are now deprecated. We will keep the current
+ * functionality for compatibility resons, but we will no longer take
+ * feature request. We do not advise adding new usages of Android Playlists.
+ * M3U files can be used as an alternative.
*/
+ @Deprecated
public static final class Playlists implements BaseColumns,
PlaylistsColumns {
/**
@@ -3143,7 +3417,7 @@
* Sub-directory of each artist containing all albums on which
* a song by the artist appears.
*/
- public static final class Albums implements AlbumColumns {
+ public static final class Albums implements BaseColumns, AlbumColumns {
public static final Uri getContentUri(String volumeName,long artistId) {
return ContentUris
.withAppendedId(Audio.Artists.getContentUri(volumeName), artistId)
@@ -3330,18 +3604,10 @@
public static class Thumbnails implements BaseColumns {
/**
* Path to the thumbnail file on disk.
- * <p>
- * Note that apps may not have filesystem permissions to directly
- * access this path. Instead of trying to open this path directly,
- * apps should use
- * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
- * access.
*
- * @deprecated Apps may not have filesystem permissions to directly
- * access this path. Instead of trying to open this path
- * directly, apps should use
- * {@link ContentResolver#loadThumbnail}
- * to gain access.
+ * @deprecated Apps that target {@link android.os.Build.VERSION_CODES#R R} and higher
+ * may not update the value of this column. However they may read the file
+ * path value from this column and use in file operations.
*/
@Deprecated
@Column(Cursor.FIELD_TYPE_STRING)
@@ -3421,7 +3687,7 @@
* @deprecated location details are no longer indexed for privacy
* reasons, and this value is now always {@code null}.
* You can still manually obtain location metadata using
- * {@link ExifInterface#getLatLong(float[])}.
+ * {@link MediaMetadataRetriever#METADATA_KEY_LOCATION}.
*/
@Deprecated
@Column(value = Cursor.FIELD_TYPE_FLOAT, readOnly = true)
@@ -3433,7 +3699,7 @@
* @deprecated location details are no longer indexed for privacy
* reasons, and this value is now always {@code null}.
* You can still manually obtain location metadata using
- * {@link ExifInterface#getLatLong(float[])}.
+ * {@link MediaMetadataRetriever#METADATA_KEY_LOCATION}.
*/
@Deprecated
@Column(value = Cursor.FIELD_TYPE_FLOAT, readOnly = true)
@@ -3676,11 +3942,9 @@
/**
* Path to the thumbnail file on disk.
*
- * @deprecated Apps may not have filesystem permissions to directly
- * access this path. Instead of trying to open this path
- * directly, apps should use
- * {@link ContentResolver#openFileDescriptor(Uri, String)}
- * to gain access.
+ * @deprecated Apps that target {@link android.os.Build.VERSION_CODES#R R} and higher
+ * may not update the value of this column. However they may read the file
+ * path value from this column and use in file operations.
*/
@Deprecated
@Column(Cursor.FIELD_TYPE_STRING)
@@ -3962,13 +4226,16 @@
/**
* Return a {@link MediaStore} Uri that is an equivalent to the given
- * {@link DocumentsProvider} Uri.
+ * {@link DocumentsProvider} Uri. This only supports {@code ExternalStorageProvider}
+ * and {@code MediaDocumentsProvider} Uris.
* <p>
* This allows apps with Storage Access Framework permissions to convert
* between {@link MediaStore} and {@link DocumentsProvider} Uris that refer
- * to the same underlying item. Note that this method doesn't grant any new
- * permissions; callers must already hold permissions obtained with
- * {@link Intent#ACTION_OPEN_DOCUMENT} or related APIs.
+ * to the same underlying item.
+ * Note that this method doesn't grant any new permissions, but it grants the same access to
+ * the Media Store Uri as the caller has to the given DocumentsProvider Uri; callers must
+ * already hold permissions for documentUri obtained with {@link Intent#ACTION_OPEN_DOCUMENT}
+ * or related APIs.
*
* @param documentUri The {@link DocumentsProvider} Uri to convert.
* @return An equivalent {@link MediaStore} Uri. Returns {@code null} if no
@@ -3990,6 +4257,94 @@
}
}
+ /**
+ * Returns true if the given application is the current system gallery of the device.
+ * <p>
+ * The system gallery is one app chosen by the OEM that has read & write access to all photos
+ * and videos on the device and control over folders in media collections.
+ *
+ * @param resolver The {@link ContentResolver} used to connect with
+ * {@link MediaStore#AUTHORITY}. Typically this value is {@link Context#getContentResolver()}.
+ * @param uid The uid to be checked if it is the current system gallery.
+ * @param packageName The package name to be checked if it is the current system gallery.
+ */
+ public static boolean isCurrentSystemGallery(
+ @NonNull ContentResolver resolver,
+ int uid,
+ @NonNull String packageName) {
+ Bundle in = new Bundle();
+ in.putInt(EXTRA_IS_SYSTEM_GALLERY_UID, uid);
+ final Bundle out = resolver.call(AUTHORITY, IS_SYSTEM_GALLERY_CALL, packageName, in);
+ return out.getBoolean(EXTRA_IS_SYSTEM_GALLERY_RESPONSE);
+ }
+
+ /**
+ * Returns an EXIF redacted version of {@code uri} i.e. a {@link Uri} with metadata such as
+ * location, GPS datestamp etc. redacted from the EXIF headers.
+ * <p>
+ * A redacted Uri can be used to share a file with another application wherein exposing
+ * sensitive information in EXIF headers is not desirable.
+ * Note:
+ * 1. Redacted uris cannot be granted write access and can neither be used to perform any kind
+ * of write operations.
+ * 2. To get a redacted uri the caller must hold read permission to {@code uri}.
+ *
+ * @param resolver The {@link ContentResolver} used to connect with
+ * {@link MediaStore#AUTHORITY}. Typically this value is gotten from
+ * {@link Context#getContentResolver()}
+ * @param uri the {@link Uri} Uri to convert
+ * @return redacted version of the {@code uri}. Returns {@code null} when the given
+ * {@link Uri} could not be found or is unsupported
+ * @throws SecurityException if the caller doesn't have the read access to {@code uri}
+ * @see #getRedactedUri(ContentResolver, List)
+ */
+ @Nullable
+ public static Uri getRedactedUri(@NonNull ContentResolver resolver, @NonNull Uri uri) {
+ try (ContentProviderClient client = resolver.acquireContentProviderClient(AUTHORITY)) {
+ final Bundle in = new Bundle();
+ in.putParcelable(EXTRA_URI, uri);
+ final Bundle out = client.call(GET_REDACTED_MEDIA_URI_CALL, null, in);
+ return out.getParcelable(EXTRA_URI);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Returns a list of EXIF redacted version of {@code uris} i.e. a {@link Uri} with metadata
+ * such as location, GPS datestamp etc. redacted from the EXIF headers.
+ * <p>
+ * A redacted Uri can be used to share a file with another application wherein exposing
+ * sensitive information in EXIF headers is not desirable.
+ * Note:
+ * 1. Order of the returned uris follow the order of the {@code uris}.
+ * 2. Redacted uris cannot be granted write access and can neither be used to perform any kind
+ * of write operations.
+ * 3. To get a redacted uri the caller must hold read permission to its corresponding uri.
+ *
+ * @param resolver The {@link ContentResolver} used to connect with
+ * {@link MediaStore#AUTHORITY}. Typically this value is gotten from
+ * {@link Context#getContentResolver()}
+ * @param uris the list of {@link Uri} Uri to convert
+ * @return a list with redacted version of {@code uris}, in the same order. Returns {@code null}
+ * when the corresponding {@link Uri} could not be found or is unsupported
+ * @throws SecurityException if the caller doesn't have the read access to all the elements
+ * in {@code uris}
+ * @see #getRedactedUri(ContentResolver, Uri)
+ */
+ @NonNull
+ public static List<Uri> getRedactedUri(@NonNull ContentResolver resolver,
+ @NonNull List<Uri> uris) {
+ try (ContentProviderClient client = resolver.acquireContentProviderClient(AUTHORITY)) {
+ final Bundle in = new Bundle();
+ in.putParcelableArrayList(EXTRA_URI_LIST, (ArrayList<? extends Parcelable>) uris);
+ final Bundle out = client.call(GET_REDACTED_MEDIA_URI_LIST_CALL, null, in);
+ return out.getParcelableArrayList(EXTRA_URI_LIST);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
/** {@hide} */
public static void resolvePlaylistMembers(@NonNull ContentResolver resolver,
@NonNull Uri playlistUri) {
@@ -4039,4 +4394,46 @@
public static void scanVolume(@NonNull ContentResolver resolver, @NonNull String volumeName) {
resolver.call(AUTHORITY, SCAN_VOLUME_CALL, volumeName, null);
}
+
+ /**
+ * Returns whether the calling app is granted {@link android.Manifest.permission#MANAGE_MEDIA}
+ * or not.
+ * <p>Declaring the permission {@link android.Manifest.permission#MANAGE_MEDIA} isn't
+ * enough to gain the access.
+ * <p>To request access, use {@link android.provider.Settings#ACTION_REQUEST_MANAGE_MEDIA}.
+ *
+ * @param context the request context
+ * @return true, the calling app is granted the permission. Otherwise, false
+ *
+ * @see android.Manifest.permission#MANAGE_MEDIA
+ * @see android.provider.Settings#ACTION_REQUEST_MANAGE_MEDIA
+ * @see #createDeleteRequest(ContentResolver, Collection)
+ * @see #createTrashRequest(ContentResolver, Collection, boolean)
+ * @see #createWriteRequest(ContentResolver, Collection)
+ */
+ @RequiresApi(Build.VERSION_CODES.S)
+ public static boolean canManageMedia(@NonNull Context context) {
+ Objects.requireNonNull(context);
+ final String packageName = context.getOpPackageName();
+ final int uid = context.getApplicationInfo().uid;
+ final String permission = android.Manifest.permission.MANAGE_MEDIA;
+
+ final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
+ final int opMode = appOps.unsafeCheckOpNoThrow(AppOpsManager.permissionToOp(permission),
+ uid, packageName);
+
+ switch (opMode) {
+ case AppOpsManager.MODE_DEFAULT:
+ return PackageManager.PERMISSION_GRANTED == context.checkPermission(
+ permission, android.os.Process.myPid(), uid);
+ case AppOpsManager.MODE_ALLOWED:
+ return true;
+ case AppOpsManager.MODE_ERRORED:
+ case AppOpsManager.MODE_IGNORED:
+ return false;
+ default:
+ Log.w(TAG, "Unknown AppOpsManager mode " + opMode);
+ return false;
+ }
+ }
}
diff --git a/apex/hiddenapi/OWNERS b/apex/hiddenapi/OWNERS
new file mode 100644
index 0000000..ac8a2b6
--- /dev/null
+++ b/apex/hiddenapi/OWNERS
@@ -0,0 +1,5 @@
+# soong-team@ as the hiddenapi files are tightly coupled with Soong
+file:platform/build/soong:/OWNERS
+
+# compat-team@ for changes to hiddenapi files
+file:tools/platform-compat:/OWNERS
diff --git a/apex/hiddenapi/hiddenapi-max-target-o-low-priority.txt b/apex/hiddenapi/hiddenapi-max-target-o-low-priority.txt
new file mode 100644
index 0000000..7c59c96
--- /dev/null
+++ b/apex/hiddenapi/hiddenapi-max-target-o-low-priority.txt
@@ -0,0 +1,27 @@
+Landroid/provider/MediaStore$Audio$AudioColumns;->ALBUM_ARTIST:Ljava/lang/String;
+Landroid/provider/MediaStore$Audio$AudioColumns;->COMPILATION:Ljava/lang/String;
+Landroid/provider/MediaStore$Audio$AudioColumns;->GENRE:Ljava/lang/String;
+Landroid/provider/MediaStore$Audio$AudioColumns;->TITLE_RESOURCE_URI:Ljava/lang/String;
+Landroid/provider/MediaStore$Audio$Media;->EXTERNAL_PATHS:[Ljava/lang/String;
+Landroid/provider/MediaStore$Audio$Radio;-><init>()V
+Landroid/provider/MediaStore$Files;->getDirectoryUri(Ljava/lang/String;)Landroid/net/Uri;
+Landroid/provider/MediaStore$Images$Media;->StoreThumbnail(Landroid/content/ContentResolver;Landroid/graphics/Bitmap;JFFI)Landroid/graphics/Bitmap;
+Landroid/provider/MediaStore$InternalThumbnails;-><init>()V
+Landroid/provider/MediaStore$InternalThumbnails;->cancelThumbnailRequest(Landroid/content/ContentResolver;JLandroid/net/Uri;J)V
+Landroid/provider/MediaStore$InternalThumbnails;->DEFAULT_GROUP_ID:I
+Landroid/provider/MediaStore$InternalThumbnails;->FULL_SCREEN_KIND:I
+Landroid/provider/MediaStore$InternalThumbnails;->getMiniThumbFromFile(Landroid/database/Cursor;Landroid/net/Uri;Landroid/content/ContentResolver;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;
+Landroid/provider/MediaStore$InternalThumbnails;->getThumbnail(Landroid/content/ContentResolver;JJILandroid/graphics/BitmapFactory$Options;Landroid/net/Uri;Z)Landroid/graphics/Bitmap;
+Landroid/provider/MediaStore$InternalThumbnails;->MICRO_KIND:I
+Landroid/provider/MediaStore$InternalThumbnails;->MINI_KIND:I
+Landroid/provider/MediaStore$InternalThumbnails;->PROJECTION:[Ljava/lang/String;
+Landroid/provider/MediaStore$InternalThumbnails;->sThumbBuf:[B
+Landroid/provider/MediaStore$InternalThumbnails;->sThumbBufLock:Ljava/lang/Object;
+Landroid/provider/MediaStore$MediaColumns;->MEDIA_SCANNER_NEW_OBJECT_ID:Ljava/lang/String;
+Landroid/provider/MediaStore;->CONTENT_AUTHORITY_SLASH:Ljava/lang/String;
+Landroid/provider/MediaStore;->getDocumentUri(Landroid/content/ContentResolver;Ljava/lang/String;Ljava/util/List;)Landroid/net/Uri;
+Landroid/provider/MediaStore;->getFilePath(Landroid/content/ContentResolver;Landroid/net/Uri;)Ljava/lang/String;
+Landroid/provider/MediaStore;->PARAM_DELETE_DATA:Ljava/lang/String;
+Landroid/provider/MediaStore;->RETRANSLATE_CALL:Ljava/lang/String;
+Landroid/provider/MediaStore;->TAG:Ljava/lang/String;
+Landroid/provider/MediaStore;->UNHIDE_CALL:Ljava/lang/String;
diff --git a/apex/testing/Android.bp b/apex/testing/Android.bp
index 2f6cc4f..41612ba 100644
--- a/apex/testing/Android.bp
+++ b/apex/testing/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "packages_providers_MediaProvider_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["packages_providers_MediaProvider_license"],
+}
+
apex_test {
name: "test_com.android.mediaprovider",
visibility: [
diff --git a/deploy.sh b/deploy.sh
index e6edcce..cc1be8e 100755
--- a/deploy.sh
+++ b/deploy.sh
@@ -8,6 +8,8 @@
adb remount
adb sync
adb shell umount /apex/com.android.mediaprovider*
+adb shell rm -rf /data/apex/active/com.android.mediaprovider*
+adb shell rm -rf /data/apex/decompressed/com.android.mediaprovider*
adb shell setprop apexd.status '""'
adb shell setprop ctl.restart apexd
adb shell rm -rf /system/priv-app/MediaProvider
diff --git a/errorprone/Android.bp b/errorprone/Android.bp
index 317c081..3f11f91 100644
--- a/errorprone/Android.bp
+++ b/errorprone/Android.bp
@@ -1,4 +1,13 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "packages_providers_MediaProvider_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["packages_providers_MediaProvider_license"],
+}
+
java_plugin {
name: "error_prone_mediaprovider",
@@ -14,11 +23,14 @@
static_libs: [
"//external/error_prone:error_prone_core",
- "//external/dagger2:dagger2-auto-service",
+ ],
+
+ libs: [
+ "//external/auto:auto_service_annotations",
],
plugins: [
- "//external/dagger2:dagger2-auto-service",
+ "//external/auto:auto_service_plugin",
],
javacflags: ["-verbose"],
diff --git a/gen_strings.py b/gen_strings.py
index 99bba8a..a3d98be 100755
--- a/gen_strings.py
+++ b/gen_strings.py
@@ -31,12 +31,6 @@
if verb == "write":
verblabel = "modify"
- verblabelcaps = verblabel[0].upper() + verblabel[1:]
- if verb == "trash":
- verblabelcaps = "Move to trash"
- if verb == "untrash":
- verblabelcaps = "Move out of trash"
-
print '''
<!-- ========================= %s STRINGS ========================= -->
''' % (verb.upper())
@@ -49,6 +43,13 @@
<item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move <xliff:g id="count" example="42">^2</xliff:g> ${datalabel}s to trash?</item>
</plurals>
''').substitute(vars()).strip("\n")
+ print Template('''
+<!-- Progress dialog message after user allows $verb permission to the $data item [CHAR LIMIT=128] -->
+<plurals name="permission_progress_${verb}_${data}">
+ <item quantity="one">Moving $datalabel to trash…</item>
+ <item quantity="other">Moving <xliff:g id="count" example="42">^1</xliff:g> ${datalabel}s to trash…</item>
+</plurals>
+''').substitute(vars()).strip("\n")
elif verb == "untrash":
print Template('''
@@ -58,6 +59,13 @@
<item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move <xliff:g id="count" example="42">^2</xliff:g> ${datalabel}s out of trash?</item>
</plurals>
''').substitute(vars()).strip("\n")
+ print Template('''
+<!-- Progress dialog message after user allows $verb permission to the $data item [CHAR LIMIT=128] -->
+<plurals name="permission_progress_${verb}_${data}">
+ <item quantity="one">Moving $datalabel out of trash…</item>
+ <item quantity="other">Moving <xliff:g id="count" example="42">^1</xliff:g> ${datalabel}s out of trash…</item>
+</plurals>
+''').substitute(vars()).strip("\n")
else:
print Template('''
@@ -67,6 +75,17 @@
<item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to $verblabel <xliff:g id="count" example="42">^2</xliff:g> ${datalabel}s?</item>
</plurals>
''').substitute(vars()).strip("\n")
+ if verb == "write":
+ actionLabel = "Modifying"
+ else:
+ actionLabel = "Deleting"
+ print Template('''
+<!-- Progress dialog message after user allows $verb permission to the $data item [CHAR LIMIT=128] -->
+<plurals name="permission_progress_${verb}_${data}">
+ <item quantity="one">$actionLabel $datalabel…</item>
+ <item quantity="other">$actionLabel <xliff:g id="count" example="42">^1</xliff:g> ${datalabel}s…</item>
+</plurals>
+''').substitute(vars()).strip("\n")
print '''
<!-- ========================= END AUTO-GENERATED BY gen_strings.py ========================= -->
diff --git a/jni/Android.bp b/jni/Android.bp
index 2f7cdb4..758bee1 100644
--- a/jni/Android.bp
+++ b/jni/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "packages_providers_MediaProvider_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["packages_providers_MediaProvider_license"],
+}
+
cc_library_shared {
name: "libfuse_jni",
diff --git a/jni/FuseDaemon.cpp b/jni/FuseDaemon.cpp
index 7a2edee..62e665a 100755
--- a/jni/FuseDaemon.cpp
+++ b/jni/FuseDaemon.cpp
@@ -79,7 +79,7 @@
// logging macros to avoid duplication.
#define TRACE_NODE(__node, __req) \
LOG(VERBOSE) << __FUNCTION__ << " : " << #__node << " = [" << get_name(__node) \
- << "] (uid=" << __req->ctx.uid << ") "
+ << "] (uid=" << (__req)->ctx.uid << ") "
#define ATRACE_NAME(name) ScopedTrace ___tracer(name)
#define ATRACE_CALL() ATRACE_NAME(__FUNCTION__)
@@ -109,10 +109,17 @@
// Stolen from: UserManagerService
constexpr int MAX_USER_ID = UINT32_MAX / PER_USER_RANGE;
+const int MY_UID = getuid();
+const int MY_USER_ID = MY_UID / PER_USER_RANGE;
+const std::string MY_USER_ID_STRING(std::to_string(MY_UID / PER_USER_RANGE));
+
// Regex copied from FileUtils.java in MediaProvider, but without media directory.
const std::regex PATTERN_OWNED_PATH(
- "^/storage/[^/]+/(?:[0-9]+/)?Android/(?:data|obb|sandbox)/([^/]+)(/?.*)?",
- std::regex_constants::icase);
+ "^/storage/[^/]+/(?:[0-9]+/)?Android/(?:data|obb)/([^/]+)(/?.*)?",
+ std::regex_constants::icase);
+
+static constexpr char TRANSFORM_SYNTHETIC_DIR[] = "synthetic";
+static constexpr char TRANSFORM_TRANSCODE_DIR[] = "transcode";
/*
* In order to avoid double caching with fuse, call fadvise on the file handles
@@ -240,23 +247,26 @@
/* Single FUSE mount */
struct fuse {
- explicit fuse(const std::string& _path)
+ explicit fuse(const std::string& _path, ino_t _ino)
: path(_path),
tracker(mediaprovider::fuse::NodeTracker(&lock)),
- root(node::CreateRoot(_path, &lock, &tracker)),
+ root(node::CreateRoot(_path, &lock, _ino, &tracker)),
mp(0),
zero_addr(0),
- disable_dentry_cache(false) {}
+ disable_dentry_cache(false),
+ passthrough(false) {}
inline bool IsRoot(const node* node) const { return node == root; }
inline string GetEffectiveRootPath() {
- if (path.find("/storage/emulated", 0) == 0) {
- return path + "/" + std::to_string(getuid() / PER_USER_RANGE);
+ if (android::base::StartsWith(path, "/storage/emulated")) {
+ return path + "/" + MY_USER_ID_STRING;
}
return path;
}
+ inline string GetTransformsDir() { return GetEffectiveRootPath() + "/.transforms"; }
+
// Note that these two (FromInode / ToInode) conversion wrappers are required
// because fuse_lowlevel_ops documents that the root inode is always one
// (see FUSE_ROOT_ID in fuse_lowlevel.h). There are no particular requirements
@@ -301,8 +311,13 @@
std::atomic_bool* active;
std::atomic_bool disable_dentry_cache;
+ std::atomic_bool passthrough;
+ // FUSE device id.
+ std::atomic_uint dev;
};
+enum class FuseOp { lookup, readdir, mknod, mkdir, create };
+
static inline string get_name(node* n) {
if (n) {
std::string name = IS_OS_DEBUGABLE ? "real_path: " + n->BuildPath() + " " : "";
@@ -377,7 +392,7 @@
// deadlocking the kernel
static void fuse_inval(fuse_session* se, fuse_ino_t parent_ino, fuse_ino_t child_ino,
const string& child_name, const string& path) {
- if (mediaprovider::fuse::containsMount(path, std::to_string(getuid() / PER_USER_RANGE))) {
+ if (mediaprovider::fuse::containsMount(path, MY_USER_ID_STRING)) {
LOG(WARNING) << "Ignoring attempt to invalidate dentry for FUSE mounts";
return;
}
@@ -389,54 +404,152 @@
}
}
-static double get_timeout(struct fuse* fuse, const string& path, bool should_inval) {
+static double get_entry_timeout(const string& path, node* node, struct fuse* fuse) {
string media_path = fuse->GetEffectiveRootPath() + "/Android/media";
- if (fuse->disable_dentry_cache || should_inval || path.find(media_path, 0) == 0 || is_package_owned_path(path, fuse->path)) {
+ if (fuse->disable_dentry_cache || node->ShouldInvalidate() ||
+ is_package_owned_path(path, fuse->path) || android::base::StartsWith(path, media_path)) {
// We set dentry timeout to 0 for the following reasons:
- // 1. Case-insensitive lookups need to invalidate other case-insensitive dentry matches
- // 2. Installd might delete Android/media/<package> dirs when app data is cleared.
- // This can leave a stale entry in the kernel dcache, and break subsequent creation of the
- // dir via FUSE.
+ // 1. The dentry cache was completely disabled
+ // 2.1 Case-insensitive lookups need to invalidate other case-insensitive dentry matches
+ // 2.2 Nodes supporting transforms need to be invalidated, so that subsequent lookups by a
+ // uid requiring a transform is guaranteed to come to the FUSE daemon.
// 3. With app data isolation enabled, app A should not guess existence of app B from the
// Android/{data,obb}/<package> paths, hence we prevent the kernel from caching that
// information.
+ // 4. Installd might delete Android/media/<package> dirs when app data is cleared.
+ // This can leave a stale entry in the kernel dcache, and break subsequent creation of the
+ // dir via FUSE.
return 0;
}
return std::numeric_limits<double>::max();
}
+static std::string get_path(node* node) {
+ const string& io_path = node->GetIoPath();
+ return io_path.empty() ? node->BuildPath() : io_path;
+}
+
+// Returns true if the path resides under .transforms/synthetic.
+// NOTE: currently only file paths corresponding to redacted URIs reside under this folder. The path
+// itself never exists and just a link for transformation.
+static inline bool is_synthetic_path(const string& path, struct fuse* fuse) {
+ return android::base::StartsWithIgnoreCase(
+ path, fuse->GetTransformsDir() + "/" + TRANSFORM_SYNTHETIC_DIR);
+}
+
+static inline bool is_transcode_supported_path(const string& path, struct fuse* fuse) {
+ // Keep in sync with MediaProvider#supportsTranscode
+ return android::base::EndsWithIgnoreCase(path, ".mp4") &&
+ android::base::StartsWithIgnoreCase(path,
+ fuse->GetEffectiveRootPath() + "/dcim/camera/");
+}
+
+static inline bool is_transforms_dir_path(const string& path, struct fuse* fuse) {
+ return android::base::StartsWithIgnoreCase(path, fuse->GetTransformsDir());
+}
+
+static std::unique_ptr<mediaprovider::fuse::FileLookupResult> validate_node_path(
+ const std::string& path, const std::string& name, fuse_req_t req, int* error_code,
+ struct fuse_entry_param* e, const FuseOp op) {
+ struct fuse* fuse = get_fuse(req);
+ const struct fuse_ctx* ctx = fuse_req_ctx(req);
+ memset(e, 0, sizeof(*e));
+
+ const bool synthetic_path = is_synthetic_path(path, fuse);
+ if (lstat(path.c_str(), &e->attr) < 0 && !(op == FuseOp::lookup && synthetic_path)) {
+ *error_code = errno;
+ return nullptr;
+ }
+
+ if (is_transforms_dir_path(path, fuse)) {
+ if (op == FuseOp::lookup) {
+ // Lookups are only allowed under .transforms/synthetic dir
+ if (!(android::base::EqualsIgnoreCase(path, fuse->GetTransformsDir()) ||
+ android::base::StartsWithIgnoreCase(
+ path, fuse->GetTransformsDir() + "/" + TRANSFORM_SYNTHETIC_DIR))) {
+ *error_code = ENONET;
+ return nullptr;
+ }
+ } else {
+ // user-code is only allowed to make lookups under .transforms dir, and that too only
+ // under .transforms/synthetic dir
+ *error_code = ENOENT;
+ return nullptr;
+ }
+ }
+
+ if (S_ISDIR(e->attr.st_mode)) {
+ // now that we have reached this point, ops on directories are safe and require no
+ // transformation.
+ return std::make_unique<mediaprovider::fuse::FileLookupResult>(0, 0, 0, true, false, "");
+ }
+
+ if (!synthetic_path && !is_transcode_supported_path(path, fuse)) {
+ // Transforms are only supported for synthetic or transcode-supported paths
+ return std::make_unique<mediaprovider::fuse::FileLookupResult>(0, 0, 0, true, false, "");
+ }
+
+ // Handle potential file transforms
+ std::unique_ptr<mediaprovider::fuse::FileLookupResult> file_lookup_result =
+ fuse->mp->FileLookup(path, req->ctx.uid, req->ctx.pid);
+
+ if (!file_lookup_result) {
+ // Fail lookup if we can't fetch FileLookupResult for path
+ LOG(WARNING) << "Failed to fetch FileLookupResult for " << path;
+ *error_code = ENOENT;
+ return nullptr;
+ }
+
+ const string& io_path = file_lookup_result->io_path;
+ // Update size with io_path size if io_path is not same as path
+ if (!io_path.empty() && (io_path != path) && (lstat(io_path.c_str(), &e->attr) < 0)) {
+ *error_code = errno;
+ return nullptr;
+ }
+
+ return file_lookup_result;
+}
+
static node* make_node_entry(fuse_req_t req, node* parent, const string& name, const string& path,
- struct fuse_entry_param* e, int* error_code) {
+ struct fuse_entry_param* e, int* error_code, const FuseOp op) {
struct fuse* fuse = get_fuse(req);
const struct fuse_ctx* ctx = fuse_req_ctx(req);
node* node;
memset(e, 0, sizeof(*e));
- if (lstat(path.c_str(), &e->attr) < 0) {
- *error_code = errno;
- return NULL;
+
+ std::unique_ptr<mediaprovider::fuse::FileLookupResult> file_lookup_result =
+ validate_node_path(path, name, req, error_code, e, op);
+ if (!file_lookup_result) {
+ // Fail lookup if we can't validate |path, |errno| would have already been set
+ return nullptr;
}
- bool should_inval = false;
- node = parent->LookupChildByName(name, true /* acquire */);
+ const bool should_invalidate = file_lookup_result->transforms_supported;
+ const bool transforms_complete = file_lookup_result->transforms_complete;
+ const int transforms = file_lookup_result->transforms;
+ const int transforms_reason = file_lookup_result->transforms_reason;
+ const string& io_path = file_lookup_result->io_path;
+
+ node = parent->LookupChildByName(name, true /* acquire */, transforms);
if (!node) {
- node = ::node::Create(parent, name, &fuse->lock, &fuse->tracker);
+ ino_t ino = e->attr.st_ino;
+ node = ::node::Create(parent, name, io_path, should_invalidate, transforms_complete,
+ transforms, transforms_reason, &fuse->lock, ino, &fuse->tracker);
} else if (!mediaprovider::fuse::containsMount(path, std::to_string(getuid() / PER_USER_RANGE))) {
- should_inval = node->HasCaseInsensitiveMatch();
// Only invalidate a path if it does not contain mount.
// Invalidate both names to ensure there's no dentry left in the kernel after the following
// operations:
// 1) touch foo, touch FOO, unlink *foo*
// 2) touch foo, touch FOO, unlink *FOO*
// Invalidating lookup_name fixes (1) and invalidating node_name fixes (2)
- // |should_inval| invalidates lookup_name by using 0 timeout below and we explicitly
+ // SetShouldInvalidate invalidates lookup_name by using 0 timeout below and we explicitly
// invalidate node_name if different case
// Note that we invalidate async otherwise we will deadlock the kernel
if (name != node->GetName()) {
- should_inval = true;
// Record that we have made a case insensitive lookup, this allows us invalidate nodes
// correctly on subsequent lookups for the case of |node|
- node->SetCaseInsensitiveMatch();
+ node->SetShouldInvalidate();
// Make copies of the node name and path so we're not attempting to acquire
// any node locks from the invalidation thread. Depending on timing, we may end
@@ -447,6 +560,12 @@
std::thread t([=]() { fuse_inval(fuse->se, parent_ino, child_ino, node_name, path); });
t.detach();
}
+
+ // This updated value allows us correctly decide if to keep_cache and use direct_io during
+ // FUSE_OPEN. Between the last lookup and this lookup, we might have deleted a cached
+ // transcoded file on the lower fs. A subsequent transcode at FUSE_READ should ensure we
+ // don't reuse any stale transcode page cache content.
+ node->SetTransformsComplete(transforms_complete);
}
TRACE_NODE(node, req);
@@ -456,11 +575,8 @@
// reuse inode numbers.
e->generation = 0;
e->ino = fuse->ToInode(node);
- e->entry_timeout = get_timeout(fuse, path, should_inval);
- e->attr_timeout = is_package_owned_path(path, fuse->path) || should_inval
- ? 0
- : std::numeric_limits<double>::max();
-
+ e->entry_timeout = get_entry_timeout(path, node, fuse);
+ e->attr_timeout = std::numeric_limits<double>::max();
return node;
}
@@ -479,15 +595,26 @@
*/
static void pf_init(void* userdata, struct fuse_conn_info* conn) {
+ struct fuse* fuse = reinterpret_cast<struct fuse*>(userdata);
+
// We don't want a getattr request with every read request
conn->want &= ~FUSE_CAP_AUTO_INVAL_DATA & ~FUSE_CAP_READDIRPLUS_AUTO;
unsigned mask = (FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE | FUSE_CAP_SPLICE_READ |
FUSE_CAP_ASYNC_READ | FUSE_CAP_ATOMIC_O_TRUNC | FUSE_CAP_WRITEBACK_CACHE |
FUSE_CAP_EXPORT_SUPPORT | FUSE_CAP_FLOCK_LOCKS);
+
+ if (fuse->passthrough) {
+ if (conn->capable & FUSE_CAP_PASSTHROUGH) {
+ mask |= FUSE_CAP_PASSTHROUGH;
+ } else {
+ LOG(WARNING) << "Passthrough feature not supported by the kernel";
+ fuse->passthrough = false;
+ }
+ }
+
conn->want |= conn->capable & mask;
conn->max_read = MAX_READ_SIZE;
- struct fuse* fuse = reinterpret_cast<struct fuse*>(userdata);
fuse->active->store(true, std::memory_order_release);
}
@@ -500,7 +627,7 @@
// Return true if the path is accessible for that uid.
static bool is_app_accessible_path(MediaProviderWrapper* mp, const string& path, uid_t uid) {
- if (uid < AID_APP_START) {
+ if (uid < AID_APP_START || uid == MY_UID) {
return true;
}
@@ -535,7 +662,7 @@
static std::regex storage_emulated_regex("^\\/storage\\/emulated\\/([0-9]+)");
static node* do_lookup(fuse_req_t req, fuse_ino_t parent, const char* name,
- struct fuse_entry_param* e, int* error_code) {
+ struct fuse_entry_param* e, int* error_code, const FuseOp op) {
struct fuse* fuse = get_fuse(req);
node* parent_node = fuse->FromInode(parent);
if (!parent_node) {
@@ -550,16 +677,15 @@
return nullptr;
}
- string child_path = parent_path + "/" + name;
-
TRACE_NODE(parent_node, req);
+ const string child_path = parent_path + "/" + name;
std::smatch match;
std::regex_search(child_path, match, storage_emulated_regex);
// Ensure the FuseDaemon user id matches the user id or cross-user lookups are allowed in
// requested path
- if (match.size() == 2 && std::to_string(getuid() / PER_USER_RANGE) != match[1].str()) {
+ if (match.size() == 2 && MY_USER_ID_STRING != match[1].str()) {
// If user id mismatch, check cross-user lookups
long userId = strtol(match[1].str().c_str(), nullptr, 10);
if (userId < 0 || userId > MAX_USER_ID ||
@@ -568,7 +694,8 @@
return nullptr;
}
}
- return make_node_entry(req, parent_node, name, child_path, e, error_code);
+
+ return make_node_entry(req, parent_node, name, child_path, e, error_code, op);
}
static void pf_lookup(fuse_req_t req, fuse_ino_t parent, const char* name) {
@@ -576,7 +703,7 @@
struct fuse_entry_param e;
int error_code = 0;
- if (do_lookup(req, parent, name, &e, &error_code)) {
+ if (do_lookup(req, parent, name, &e, &error_code, FuseOp::lookup)) {
fuse_reply_entry(req, &e);
} else {
CHECK(error_code != 0);
@@ -617,6 +744,16 @@
fuse_reply_none(req);
}
+static void pf_fallocate(fuse_req_t req, fuse_ino_t ino, int mode, off_t offset, off_t length,
+ fuse_file_info* fi) {
+ ATRACE_CALL();
+ struct fuse* fuse = get_fuse(req);
+
+ handle* h = reinterpret_cast<handle*>(fi->fh);
+ auto err = fallocate(h->fd, mode, offset, length);
+ fuse_reply_err(req, err ? errno : 0);
+}
+
static void pf_getattr(fuse_req_t req,
fuse_ino_t ino,
struct fuse_file_info* fi) {
@@ -627,7 +764,7 @@
fuse_reply_err(req, ENOENT);
return;
}
- string path = node->BuildPath();
+ const string& path = get_path(node);
if (!is_app_accessible_path(fuse->mp, path, req->ctx.uid)) {
fuse_reply_err(req, ENOENT);
return;
@@ -639,8 +776,7 @@
if (lstat(path.c_str(), &s) < 0) {
fuse_reply_err(req, errno);
} else {
- fuse_reply_attr(req, &s, is_package_owned_path(path, fuse->path) ?
- 0 : std::numeric_limits<double>::max());
+ fuse_reply_attr(req, &s, std::numeric_limits<double>::max());
}
}
@@ -656,7 +792,7 @@
fuse_reply_err(req, ENOENT);
return;
}
- string path = node->BuildPath();
+ const string& path = get_path(node);
if (!is_app_accessible_path(fuse->mp, path, req->ctx.uid)) {
fuse_reply_err(req, ENOENT);
return;
@@ -669,8 +805,16 @@
fd = h->fd;
} else {
const struct fuse_ctx* ctx = fuse_req_ctx(req);
- int status = fuse->mp->IsOpenAllowed(path, ctx->uid, true);
- if (status) {
+ std::unique_ptr<FileOpenResult> result = fuse->mp->OnFileOpen(
+ path, path, ctx->uid, ctx->pid, node->GetTransformsReason(), true /* for_write */,
+ false /* redact */, false /* log_transforms_metrics */);
+
+ if (!result) {
+ fuse_reply_err(req, EFAULT);
+ return;
+ }
+
+ if (result->status) {
fuse_reply_err(req, EACCES);
return;
}
@@ -735,15 +879,14 @@
}
lstat(path.c_str(), attr);
- fuse_reply_attr(req, attr, is_package_owned_path(path, fuse->path) ?
- 0 : std::numeric_limits<double>::max());
+ fuse_reply_attr(req, attr, std::numeric_limits<double>::max());
}
static void pf_canonical_path(fuse_req_t req, fuse_ino_t ino)
{
struct fuse* fuse = get_fuse(req);
node* node = fuse->FromInode(ino);
- string path = node ? node->BuildPath() : "";
+ const string& path = node ? get_path(node) : "";
if (node && is_app_accessible_path(fuse->mp, path, req->ctx.uid)) {
// TODO(b/147482155): Check that uid has access to |path| and its contents
@@ -783,7 +926,7 @@
int error_code = 0;
struct fuse_entry_param e;
- if (make_node_entry(req, parent_node, name, child_path, &e, &error_code)) {
+ if (make_node_entry(req, parent_node, name, child_path, &e, &error_code, FuseOp::mknod)) {
fuse_reply_entry(req, &e);
} else {
CHECK(error_code != 0);
@@ -827,7 +970,7 @@
int error_code = 0;
struct fuse_entry_param e;
- if (make_node_entry(req, parent_node, name, child_path, &e, &error_code)) {
+ if (make_node_entry(req, parent_node, name, child_path, &e, &error_code, FuseOp::mkdir)) {
fuse_reply_entry(req, &e);
} else {
CHECK(error_code != 0);
@@ -860,12 +1003,8 @@
return;
}
- node* child_node = parent_node->LookupChildByName(name, false /* acquire */);
- TRACE_NODE(child_node, req);
- if (child_node) {
- child_node->SetDeleted();
- }
-
+ // TODO(b/169306422): Log each deleted node
+ parent_node->SetDeletedForChild(name);
fuse_reply_err(req, 0);
}
@@ -882,6 +1021,14 @@
fuse_reply_err(req, ENOENT);
return;
}
+
+ if (is_transforms_dir_path(parent_path, fuse)) {
+ // .transforms is a special daemon controlled dir so apps shouldn't be able to see it via
+ // readdir, and any dir operations attempted on it should fail
+ fuse_reply_err(req, ENOENT);
+ return;
+ }
+
TRACE_NODE(parent_node, req);
const string child_path = parent_path + "/" + name;
@@ -929,6 +1076,12 @@
return ENOENT;
}
+ if (is_transforms_dir_path(old_parent_path, fuse)) {
+ // .transforms is a special daemon controlled dir so apps shouldn't be able to see it via
+ // readdir, and any dir operations attempted on it should fail
+ return ENOENT;
+ }
+
node* new_parent_node = fuse->FromInode(new_parent);
if (!new_parent_node) return ENOENT;
const string new_parent_path = new_parent_node->BuildPath();
@@ -946,10 +1099,7 @@
TRACE_NODE(old_parent_node, req);
TRACE_NODE(new_parent_node, req);
- node* child_node = old_parent_node->LookupChildByName(name, true /* acquire */);
- TRACE_NODE(child_node, req) << "old_child";
-
- const string old_child_path = child_node->BuildPath();
+ const string old_child_path = old_parent_path + "/" + name;
const string new_child_path = new_parent_path + "/" + new_name;
if (android::base::EqualsIgnoreCase(fuse->GetEffectiveRootPath() + "/android", old_child_path)) {
@@ -962,11 +1112,9 @@
// TODO(b/145663158): Lookups can go out of sync if file/directory is actually moved but
// EFAULT/EIO is reported due to JNI exception.
if (res == 0) {
- child_node->Rename(new_name, new_parent_node);
+ // TODO(b/169306422): Log each renamed node
+ old_parent_node->RenameChild(name, new_name, new_parent_node);
}
- TRACE_NODE(child_node, req) << "new_child";
-
- child_node->Release(1);
return res;
}
@@ -984,40 +1132,76 @@
}
*/
-static handle* create_handle_for_node(struct fuse* fuse, const string& path, int fd, node* node,
- const RedactionInfo* ri, int* keep_cache) {
+static handle* create_handle_for_node(struct fuse* fuse, const string& path, int fd, uid_t uid,
+ uid_t transforms_uid, node* node, const RedactionInfo* ri,
+ int* keep_cache) {
std::lock_guard<std::recursive_mutex> guard(fuse->lock);
- // We don't want to use the FUSE VFS cache in two cases:
- // 1. When redaction is needed because app A with EXIF access might access
- // a region that should have been redacted for app B without EXIF access, but app B on
- // a subsequent read, will be able to see the EXIF data because the read request for
- // that region will be served from cache and not get to the FUSE daemon
- // 2. When the file has a read or write lock on it. This means that the MediaProvider
- // has given an fd to the lower file system to an app. There are two cases where using
- // the cache in this case can be a problem:
- // a. Writing to a FUSE fd with caching enabled will use the write-back cache and a
- // subsequent read from the lower fs fd will not see the write.
- // b. Reading from a FUSE fd with caching enabled may not see the latest writes using
- // the lower fs fd because those writes did not go through the FUSE layer and reads from
- // FUSE after that write may be served from cache
- bool has_redacted = node->HasRedactedCache();
- bool redaction_needed = ri->isRedactionNeeded();
- bool is_redaction_change =
- (redaction_needed && !has_redacted) || (!redaction_needed && has_redacted);
- bool is_cached_file_open = node->HasCachedHandle();
- if (!is_cached_file_open && is_redaction_change) {
- node->SetRedactedCache(redaction_needed);
- // Purges stale page cache before open
- *keep_cache = 0;
- } else {
- *keep_cache = 1;
+ bool redaction_needed = ri->isRedactionNeeded();
+ handle* handle = nullptr;
+ int transforms = node->GetTransforms();
+ bool transforms_complete = node->IsTransformsComplete();
+ if (transforms_uid > 0) {
+ CHECK(transforms);
}
- bool direct_io = (is_cached_file_open && is_redaction_change) || is_file_locked(fd, path);
- handle* h = new handle(fd, ri, !direct_io);
- node->AddHandle(h);
- return h;
+ if (fuse->passthrough) {
+ *keep_cache = transforms_complete;
+ // We only enabled passthrough iff these 2 conditions hold
+ // 1. Redaction is not needed
+ // 2. Node transforms are completed, e.g transcoding.
+ // (2) is important because we transcode lazily (on the first read) and with passthrough,
+ // we will never get a read into the FUSE daemon, so passthrough would have returned
+ // arbitrary bytes the first time around. However, if we ensure that transforms are
+ // completed, then it's safe to use passthrough. Additionally, transcoded nodes never
+ // require redaction so (2) implies (1)
+ handle = new struct handle(fd, ri, true /* cached */,
+ !redaction_needed && transforms_complete /* passthrough */, uid,
+ transforms_uid);
+ } else {
+ // Without fuse->passthrough, we don't want to use the FUSE VFS cache in two cases:
+ // 1. When redaction is needed because app A with EXIF access might access
+ // a region that should have been redacted for app B without EXIF access, but app B on
+ // a subsequent read, will be able to see the EXIF data because the read request for
+ // that region will be served from cache and not get to the FUSE daemon
+ // 2. When the file has a read or write lock on it. This means that the MediaProvider
+ // has given an fd to the lower file system to an app. There are two cases where using
+ // the cache in this case can be a problem:
+ // a. Writing to a FUSE fd with caching enabled will use the write-back cache and a
+ // subsequent read from the lower fs fd will not see the write.
+ // b. Reading from a FUSE fd with caching enabled may not see the latest writes using
+ // the lower fs fd because those writes did not go through the FUSE layer and reads from
+ // FUSE after that write may be served from cache
+ bool has_redacted = node->HasRedactedCache();
+ bool is_redaction_change =
+ (redaction_needed && !has_redacted) || (!redaction_needed && has_redacted);
+ bool is_cached_file_open = node->HasCachedHandle();
+ bool direct_io = (is_cached_file_open && is_redaction_change) || is_file_locked(fd, path);
+
+ if (!is_cached_file_open && is_redaction_change) {
+ node->SetRedactedCache(redaction_needed);
+ // Purges stale page cache before open
+ *keep_cache = 0;
+ } else {
+ *keep_cache = transforms_complete;
+ }
+ handle = new struct handle(fd, ri, !direct_io /* cached */, false /* passthrough */, uid,
+ transforms_uid);
+ }
+
+ node->AddHandle(handle);
+ return handle;
+}
+
+bool do_passthrough_enable(fuse_req_t req, struct fuse_file_info* fi, unsigned int fd) {
+ int passthrough_fh = fuse_passthrough_enable(req, fd);
+
+ if (passthrough_fh <= 0) {
+ return false;
+ }
+
+ fi->passthrough_fh = passthrough_fh;
+ return true;
}
static void pf_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi) {
@@ -1029,22 +1213,39 @@
return;
}
const struct fuse_ctx* ctx = fuse_req_ctx(req);
- const string path = node->BuildPath();
- if (!is_app_accessible_path(fuse->mp, path, ctx->uid)) {
+ const string& io_path = get_path(node);
+ const string& build_path = node->BuildPath();
+ if (!is_app_accessible_path(fuse->mp, io_path, ctx->uid)) {
fuse_reply_err(req, ENOENT);
return;
}
- TRACE_NODE(node, req) << (is_requesting_write(fi->flags) ? "write" : "read");
+ bool for_write = is_requesting_write(fi->flags);
+
+ if (for_write && node->GetTransforms()) {
+ TRACE_NODE(node, req) << "write with transforms";
+ } else {
+ TRACE_NODE(node, req) << (for_write ? "write" : "read");
+ }
if (fi->flags & O_DIRECT) {
fi->flags &= ~O_DIRECT;
fi->direct_io = true;
}
- int status = fuse->mp->IsOpenAllowed(path, ctx->uid, is_requesting_write(fi->flags));
- if (status) {
- fuse_reply_err(req, status);
+ // Force permission check with the build path because the MediaProvider database might not be
+ // aware of the io_path
+ // We don't redact if the caller was granted write permission for this file
+ std::unique_ptr<FileOpenResult> result = fuse->mp->OnFileOpen(
+ build_path, io_path, ctx->uid, ctx->pid, node->GetTransformsReason(), for_write,
+ !for_write /* redact */, true /* log_transforms_metrics */);
+ if (!result) {
+ fuse_reply_err(req, EFAULT);
+ return;
+ }
+
+ if (result->status) {
+ fuse_reply_err(req, result->status);
return;
}
@@ -1060,31 +1261,31 @@
open_flags &= ~O_APPEND;
}
- const int fd = open(path.c_str(), open_flags);
+ const int fd = open(io_path.c_str(), open_flags);
if (fd < 0) {
fuse_reply_err(req, errno);
return;
}
- // We don't redact if the caller was granted write permission for this file
- std::unique_ptr<RedactionInfo> ri;
- if (is_requesting_write(fi->flags)) {
- ri = std::make_unique<RedactionInfo>();
- } else {
- ri = fuse->mp->GetRedactionInfo(path, req->ctx.uid, req->ctx.pid);
- }
-
- if (!ri) {
- close(fd);
- fuse_reply_err(req, EFAULT);
- return;
- }
-
int keep_cache = 1;
- handle* h = create_handle_for_node(fuse, path, fd, node, ri.release(), &keep_cache);
+ handle* h = create_handle_for_node(fuse, io_path, fd, result->uid, result->transforms_uid, node,
+ result->redaction_info.release(), &keep_cache);
fi->fh = ptr_to_id(h);
fi->keep_cache = keep_cache;
fi->direct_io = !h->cached;
+
+ // TODO(b/173190192) ensuring that h->cached must be enabled in order to
+ // user FUSE passthrough is a conservative rule and might be dropped as
+ // soon as demonstrated its correctness.
+ if (h->passthrough) {
+ if (!do_passthrough_enable(req, fi, fd)) {
+ // TODO: Should we crash here so we can find errors easily?
+ PLOG(ERROR) << "Passthrough OPEN failed for " << io_path;
+ fuse_reply_err(req, EFAULT);
+ return;
+ }
+ }
+
fuse_reply_open(req, fi);
}
@@ -1166,6 +1367,18 @@
handle* h = reinterpret_cast<handle*>(fi->fh);
struct fuse* fuse = get_fuse(req);
+ node* node = fuse->FromInode(ino);
+
+ if (!node->IsTransformsComplete()) {
+ if (!fuse->mp->Transform(node->BuildPath(), node->GetIoPath(), node->GetTransforms(),
+ node->GetTransformsReason(), req->ctx.uid, h->uid,
+ h->transforms_uid)) {
+ fuse_reply_err(req, EFAULT);
+ return;
+ }
+ node->SetTransformsComplete(true);
+ }
+
fuse->fadviser.Record(h->fd, size);
if (h->ri->isRedactionNeeded()) {
@@ -1237,14 +1450,6 @@
fuse_reply_write(req, size);
}
#endif
-static void pf_flush(fuse_req_t req,
- fuse_ino_t ino,
- struct fuse_file_info* fi) {
- ATRACE_CALL();
- struct fuse* fuse = get_fuse(req);
- TRACE_NODE(nullptr, req) << "noop";
- fuse_reply_err(req, 0);
-}
static void pf_release(fuse_req_t req,
fuse_ino_t ino,
@@ -1389,7 +1594,7 @@
h->next_off++;
if (plus) {
int error_code = 0;
- if (do_lookup(req, ino, de->d_name.c_str(), &e, &error_code)) {
+ if (do_lookup(req, ino, de->d_name.c_str(), &e, &error_code, FuseOp::readdir)) {
entry_size = fuse_add_direntry_plus(req, buf + used, len - used, de->d_name.c_str(),
&e, h->next_off);
} else {
@@ -1541,7 +1746,16 @@
return;
}
- status = fuse->mp->IsOpenAllowed(path, req->ctx.uid, for_write);
+ std::unique_ptr<FileOpenResult> result = fuse->mp->OnFileOpen(
+ path, path, req->ctx.uid, req->ctx.pid, node->GetTransformsReason(), for_write,
+ false /* redact */, false /* log_transforms_metrics */);
+ if (!result) {
+ status = EFAULT;
+ }
+
+ if (result->status) {
+ status = EACCES;
+ }
}
fuse_reply_err(req, status);
@@ -1600,7 +1814,8 @@
int error_code = 0;
struct fuse_entry_param e;
- node* node = make_node_entry(req, parent_node, name, child_path, &e, &error_code);
+ node* node =
+ make_node_entry(req, parent_node, name, child_path, &e, &error_code, FuseOp::create);
TRACE_NODE(node, req);
if (!node) {
CHECK(error_code != 0);
@@ -1616,10 +1831,23 @@
// to the file before all the EXIF content is written. We could special case reads before the
// first close after a file has just been created.
int keep_cache = 1;
- handle* h = create_handle_for_node(fuse, child_path, fd, node, new RedactionInfo(), &keep_cache);
+ handle* h = create_handle_for_node(fuse, child_path, fd, req->ctx.uid, 0 /* transforms_uid */,
+ node, new RedactionInfo(), &keep_cache);
fi->fh = ptr_to_id(h);
fi->keep_cache = keep_cache;
fi->direct_io = !h->cached;
+
+ // TODO(b/173190192) ensuring that h->cached must be enabled in order to
+ // user FUSE passthrough is a conservative rule and might be dropped as
+ // soon as demonstrated its correctness.
+ if (h->passthrough) {
+ if (!do_passthrough_enable(req, fi, fd)) {
+ PLOG(ERROR) << "Passthrough CREATE failed for " << child_path;
+ fuse_reply_err(req, EFAULT);
+ return;
+ }
+ }
+
fuse_reply_create(req, &e, fi);
}
/*
@@ -1683,7 +1911,7 @@
/*.link = pf_link,*/
.open = pf_open, .read = pf_read,
/*.write = pf_write,*/
- .flush = pf_flush,
+ /*.flush = pf_flush,*/
.release = pf_release, .fsync = pf_fsync, .opendir = pf_opendir, .readdir = pf_readdir,
.releasedir = pf_releasedir, .fsyncdir = pf_fsyncdir, .statfs = pf_statfs,
/*.setxattr = pf_setxattr,
@@ -1699,8 +1927,8 @@
.write_buf = pf_write_buf,
/*.retrieve_reply = pf_retrieve_reply,*/
.forget_multi = pf_forget_multi,
- /*.flock = pf_flock,
- .fallocate = pf_fallocate,*/
+ /*.flock = pf_flock,*/
+ .fallocate = pf_fallocate,
.readdirplus = pf_readdirplus,
/*.copy_file_range = pf_copy_file_range,*/
};
@@ -1726,6 +1954,13 @@
}
bool FuseDaemon::ShouldOpenWithFuse(int fd, bool for_read, const std::string& path) {
+ if (fuse->passthrough) {
+ // Always open with FUSE if passthrough is enabled. This avoids the delicate file lock
+ // acquisition below to ensure VFS cache consistency and doesn't impact filesystem
+ // performance since read(2)/write(2) happen in the kernel
+ return true;
+ }
+
bool use_fuse = false;
if (active.load(std::memory_order_acquire)) {
@@ -1802,7 +2037,7 @@
return;
}
- struct fuse fuse_default(path);
+ struct fuse fuse_default(path, stat.st_ino);
fuse_default.mp = ∓
// fuse_default is stack allocated, but it's safe to save it as an instance variable because
// this method blocks and FuseDaemon#active tells if we are currently blocking
@@ -1822,12 +2057,16 @@
fuse_set_log_func(fuse_logger);
}
- uid_t userId = getuid() / PER_USER_RANGE;
- if (userId != 0 && mp.IsAppCloneUser(userId)) {
+ if (MY_USER_ID != 0 && mp.IsAppCloneUser(MY_USER_ID)) {
// Disable dentry caching for the app clone user
fuse->disable_dentry_cache = true;
}
+ fuse->passthrough = android::base::GetBoolProperty("persist.sys.fuse.passthrough.enable", false);
+ if (fuse->passthrough) {
+ LOG(INFO) << "Using FUSE passthrough";
+ }
+
struct fuse_session
* se = fuse_session_new(&args, &ops, sizeof(ops), &fuse_default);
if (!se) {
@@ -1856,5 +2095,42 @@
LOG(INFO) << "Ended fuse";
return;
}
+
+const string FuseDaemon::GetOriginalMediaFormatFilePath(int fd) const {
+ struct stat s;
+ memset(&s, 0, sizeof(s));
+ if (fstat(fd, &s) < 0) {
+ PLOG(DEBUG) << "GetOriginalMediaFormatFilePath fstat failed.";
+ return string();
+ }
+
+ ino_t ino = s.st_ino;
+ dev_t dev = s.st_dev;
+
+ dev_t fuse_dev = fuse->dev.load(std::memory_order_acquire);
+ if (dev != fuse_dev) {
+ PLOG(DEBUG) << "GetOriginalMediaFormatFilePath FUSE device id does not match.";
+ return string();
+ }
+
+ const node* node = node::LookupInode(fuse->root, ino);
+ if (!node) {
+ PLOG(DEBUG) << "GetOriginalMediaFormatFilePath no node found with given ino";
+ return string();
+ }
+
+ return node->BuildPath();
+}
+
+void FuseDaemon::InitializeDeviceId(const std::string& path) {
+ struct stat stat;
+
+ if (lstat(path.c_str(), &stat)) {
+ PLOG(ERROR) << "InitializeDeviceId failed to stat given path " << path;
+ return;
+ }
+
+ fuse->dev.store(stat.st_dev, std::memory_order_release);
+}
} //namespace fuse
} // namespace mediaprovider
diff --git a/jni/FuseDaemon.h b/jni/FuseDaemon.h
index 3c4b947..f7c5614 100644
--- a/jni/FuseDaemon.h
+++ b/jni/FuseDaemon.h
@@ -54,6 +54,16 @@
*/
void InvalidateFuseDentryCache(const std::string& path);
+ /**
+ * Return path of the original media format file for the given file descriptor.
+ */
+ const std::string GetOriginalMediaFormatFilePath(int fd) const;
+
+ /**
+ * Initialize device id for the FUSE daemon with the FUSE device id of the given path.
+ */
+ void InitializeDeviceId(const std::string& path);
+
private:
FuseDaemon(const FuseDaemon&) = delete;
void operator=(const FuseDaemon&) = delete;
diff --git a/jni/MediaProviderWrapper.cpp b/jni/MediaProviderWrapper.cpp
index 734ae97..9f8a759 100644
--- a/jni/MediaProviderWrapper.cpp
+++ b/jni/MediaProviderWrapper.cpp
@@ -56,30 +56,17 @@
return false;
}
-std::unique_ptr<RedactionInfo> getRedactionInfoInternal(JNIEnv* env, jobject media_provider_object,
- jmethodID mid_get_redaction_ranges,
- uid_t uid, pid_t tid, const string& path) {
- ScopedLocalRef<jstring> j_path(env, env->NewStringUTF(path.c_str()));
- ScopedLocalRef<jlongArray> redaction_ranges_local_ref(
- env, static_cast<jlongArray>(env->CallObjectMethod(
- media_provider_object, mid_get_redaction_ranges, j_path.get(), uid, tid)));
- ScopedLongArrayRO redaction_ranges(env, redaction_ranges_local_ref.get());
-
- if (CheckForJniException(env)) {
- return nullptr;
+/**
+ * Auxiliary for caching class fields
+ */
+static jfieldID CacheField(JNIEnv* env, jclass clazz, const char field_name[], const char type[]) {
+ jfieldID fid;
+ string actual_field_name(field_name);
+ fid = env->GetFieldID(clazz, actual_field_name.c_str(), type);
+ if (!fid) {
+ LOG(FATAL) << "Error caching field: " << field_name << type;
}
-
- std::unique_ptr<RedactionInfo> ri;
- if (redaction_ranges.size() % 2) {
- LOG(ERROR) << "Error while calculating redaction ranges: array length is uneven";
- } else if (redaction_ranges.size() > 0) {
- ri = std::make_unique<RedactionInfo>(redaction_ranges.size() / 2, redaction_ranges.get());
- } else {
- // No ranges to redact
- ri = std::make_unique<RedactionInfo>();
- }
-
- return ri;
+ return fid;
}
int insertFileInternal(JNIEnv* env, jobject media_provider_object, jmethodID mid_insert_file,
@@ -104,18 +91,6 @@
return res;
}
-int isOpenAllowedInternal(JNIEnv* env, jobject media_provider_object, jmethodID mid_is_open_allowed,
- const string& path, uid_t uid, bool for_write) {
- ScopedLocalRef<jstring> j_path(env, env->NewStringUTF(path.c_str()));
- int res = env->CallIntMethod(media_provider_object, mid_is_open_allowed, j_path.get(), uid,
- for_write);
-
- if (CheckForJniException(env)) {
- return EFAULT;
- }
- return res;
-}
-
int isMkdirOrRmdirAllowedInternal(JNIEnv* env, jobject media_provider_object,
jmethodID mid_is_mkdir_or_rmdir_allowed, const string& path,
uid_t uid, bool forCreate) {
@@ -253,13 +228,13 @@
media_provider_class_ = reinterpret_cast<jclass>(env->NewGlobalRef(media_provider_class_));
// Cache methods - Before calling a method, make sure you cache it here
- mid_get_redaction_ranges_ = CacheMethod(env, "getRedactionRanges", "(Ljava/lang/String;II)[J",
- /*is_static*/ false);
mid_insert_file_ = CacheMethod(env, "insertFileIfNecessary", "(Ljava/lang/String;I)I",
/*is_static*/ false);
mid_delete_file_ = CacheMethod(env, "deleteFile", "(Ljava/lang/String;I)I", /*is_static*/ false);
- mid_is_open_allowed_ = CacheMethod(env, "isOpenAllowed", "(Ljava/lang/String;IZ)I",
- /*is_static*/ false);
+ mid_on_file_open_ = CacheMethod(env, "onFileOpen",
+ "(Ljava/lang/String;Ljava/lang/String;IIIZZZ)Lcom/android/"
+ "providers/media/FileOpenResult;",
+ /*is_static*/ false);
mid_is_mkdir_or_rmdir_allowed_ = CacheMethod(env, "isDirectoryCreationOrDeletionAllowed",
"(Ljava/lang/String;IZ)I", /*is_static*/ false);
mid_is_opendir_allowed_ = CacheMethod(env, "isOpendirAllowed", "(Ljava/lang/String;IZ)I",
@@ -278,6 +253,42 @@
/*is_static*/ false);
mid_is_app_clone_user_ = CacheMethod(env, "isAppCloneUser", "(I)Z",
/*is_static*/ false);
+ mid_transform_ = CacheMethod(env, "transform", "(Ljava/lang/String;Ljava/lang/String;IIIII)Z",
+ /*is_static*/ false);
+ mid_file_lookup_ =
+ CacheMethod(env, "onFileLookup",
+ "(Ljava/lang/String;II)Lcom/android/providers/media/FileLookupResult;",
+ /*is_static*/ false);
+
+ // FileLookupResult
+ file_lookup_result_class_ = env->FindClass("com/android/providers/media/FileLookupResult");
+ if (!file_lookup_result_class_) {
+ LOG(FATAL) << "Could not find class FileLookupResult";
+ }
+ file_lookup_result_class_ =
+ reinterpret_cast<jclass>(env->NewGlobalRef(file_lookup_result_class_));
+ fid_file_lookup_transforms_ = CacheField(env, file_lookup_result_class_, "transforms", "I");
+ fid_file_lookup_transforms_reason_ =
+ CacheField(env, file_lookup_result_class_, "transformsReason", "I");
+ fid_file_lookup_uid_ = CacheField(env, file_lookup_result_class_, "uid", "I");
+ fid_file_lookup_transforms_complete_ =
+ CacheField(env, file_lookup_result_class_, "transformsComplete", "Z");
+ fid_file_lookup_transforms_supported_ =
+ CacheField(env, file_lookup_result_class_, "transformsSupported", "Z");
+ fid_file_lookup_io_path_ =
+ CacheField(env, file_lookup_result_class_, "ioPath", "Ljava/lang/String;");
+
+ // FileOpenResult
+ file_open_result_class_ = env->FindClass("com/android/providers/media/FileOpenResult");
+ if (!file_open_result_class_) {
+ LOG(FATAL) << "Could not find class FileOpenResult";
+ }
+ file_open_result_class_ = reinterpret_cast<jclass>(env->NewGlobalRef(file_open_result_class_));
+ fid_file_open_status_ = CacheField(env, file_open_result_class_, "status", "I");
+ fid_file_open_uid_ = CacheField(env, file_open_result_class_, "uid", "I");
+ fid_file_open_transforms_uid_ = CacheField(env, file_open_result_class_, "transformsUid", "I");
+ fid_file_open_redaction_ranges_ =
+ CacheField(env, file_open_result_class_, "redactionRanges", "[J");
}
MediaProviderWrapper::~MediaProviderWrapper() {
@@ -286,23 +297,6 @@
env->DeleteGlobalRef(media_provider_class_);
}
-std::unique_ptr<RedactionInfo> MediaProviderWrapper::GetRedactionInfo(const string& path, uid_t uid,
- pid_t tid) {
- if (shouldBypassMediaProvider(uid) || !GetBoolProperty(kPropRedactionEnabled, true)) {
- return std::make_unique<RedactionInfo>();
- }
-
- // Default value in case JNI thread was being terminated, causes the read to fail.
- std::unique_ptr<RedactionInfo> res = nullptr;
-
- JNIEnv* env = MaybeAttachCurrentThread();
- auto ri = getRedactionInfoInternal(env, media_provider_object_, mid_get_redaction_ranges_, uid,
- tid, path);
- res = std::move(ri);
-
- return res;
-}
-
int MediaProviderWrapper::InsertFile(const string& path, uid_t uid) {
if (uid == ROOT_UID) {
return 0;
@@ -322,14 +316,53 @@
return deleteFileInternal(env, media_provider_object_, mid_delete_file_, path, uid);
}
-int MediaProviderWrapper::IsOpenAllowed(const string& path, uid_t uid, bool for_write) {
+std::unique_ptr<FileOpenResult> MediaProviderWrapper::OnFileOpen(const string& path,
+ const string& io_path, uid_t uid,
+ pid_t tid, int transforms_reason,
+ bool for_write, bool redact,
+ bool log_transforms_metrics) {
+ JNIEnv* env = MaybeAttachCurrentThread();
if (shouldBypassMediaProvider(uid)) {
- return 0;
+ return std::make_unique<FileOpenResult>(0, uid, 0 /* transforms_uid */, new RedactionInfo());
}
- JNIEnv* env = MaybeAttachCurrentThread();
- return isOpenAllowedInternal(env, media_provider_object_, mid_is_open_allowed_, path, uid,
- for_write);
+ ScopedLocalRef<jstring> j_path(env, env->NewStringUTF(path.c_str()));
+ ScopedLocalRef<jstring> j_io_path(env, env->NewStringUTF(io_path.c_str()));
+ ScopedLocalRef<jobject> j_res_file_open_object(
+ env, env->CallObjectMethod(media_provider_object_, mid_on_file_open_, j_path.get(),
+ j_io_path.get(), uid, tid, transforms_reason, for_write,
+ redact, log_transforms_metrics));
+
+ if (CheckForJniException(env)) {
+ return nullptr;
+ }
+
+ int status = env->GetIntField(j_res_file_open_object.get(), fid_file_open_status_);
+ int original_uid = env->GetIntField(j_res_file_open_object.get(), fid_file_open_uid_);
+ int transforms_uid =
+ env->GetIntField(j_res_file_open_object.get(), fid_file_open_transforms_uid_);
+
+ if (redact) {
+ ScopedLocalRef<jlongArray> redaction_ranges_local_ref(
+ env, static_cast<jlongArray>(env->GetObjectField(j_res_file_open_object.get(),
+ fid_file_open_redaction_ranges_)));
+ ScopedLongArrayRO redaction_ranges(env, redaction_ranges_local_ref.get());
+
+ std::unique_ptr<RedactionInfo> ri;
+ if (redaction_ranges.size() % 2) {
+ LOG(ERROR) << "Error while calculating redaction ranges: array length is uneven";
+ } else if (redaction_ranges.size() > 0) {
+ ri = std::make_unique<RedactionInfo>(redaction_ranges.size() / 2,
+ redaction_ranges.get());
+ } else {
+ // No ranges to redact
+ ri = std::make_unique<RedactionInfo>();
+ }
+ return std::make_unique<FileOpenResult>(status, original_uid, transforms_uid, ri.release());
+ } else {
+ return std::make_unique<FileOpenResult>(status, original_uid, transforms_uid,
+ new RedactionInfo());
+ }
}
int MediaProviderWrapper::IsCreatingDirAllowed(const string& path, uid_t uid) {
@@ -440,6 +473,57 @@
return res;
}
+std::unique_ptr<FileLookupResult> MediaProviderWrapper::FileLookup(const std::string& path,
+ uid_t uid, pid_t tid) {
+ JNIEnv* env = MaybeAttachCurrentThread();
+
+ ScopedLocalRef<jstring> j_path(env, env->NewStringUTF(path.c_str()));
+
+ ScopedLocalRef<jobject> j_res_file_lookup_object(
+ env, env->CallObjectMethod(media_provider_object_, mid_file_lookup_, j_path.get(), uid,
+ tid));
+
+ if (CheckForJniException(env)) {
+ return nullptr;
+ }
+
+ int transforms = env->GetIntField(j_res_file_lookup_object.get(), fid_file_lookup_transforms_);
+ int transforms_reason =
+ env->GetIntField(j_res_file_lookup_object.get(), fid_file_lookup_transforms_reason_);
+ int original_uid = env->GetIntField(j_res_file_lookup_object.get(), fid_file_lookup_uid_);
+ bool transforms_complete = env->GetBooleanField(j_res_file_lookup_object.get(),
+ fid_file_lookup_transforms_complete_);
+ bool transforms_supported = env->GetBooleanField(j_res_file_lookup_object.get(),
+ fid_file_lookup_transforms_supported_);
+ ScopedLocalRef<jstring> j_io_path(
+ env,
+ (jstring)env->GetObjectField(j_res_file_lookup_object.get(), fid_file_lookup_io_path_));
+ ScopedUtfChars j_io_path_utf(env, j_io_path.get());
+
+ std::unique_ptr<FileLookupResult> file_lookup_result = std::make_unique<FileLookupResult>(
+ transforms, transforms_reason, original_uid, transforms_complete, transforms_supported,
+ string(j_io_path_utf.c_str()));
+ return file_lookup_result;
+}
+
+bool MediaProviderWrapper::Transform(const std::string& src, const std::string& dst, int transforms,
+ int transforms_reason, uid_t read_uid, uid_t open_uid,
+ uid_t transforms_uid) {
+ JNIEnv* env = MaybeAttachCurrentThread();
+
+ ScopedLocalRef<jstring> j_src(env, env->NewStringUTF(src.c_str()));
+ ScopedLocalRef<jstring> j_dst(env, env->NewStringUTF(dst.c_str()));
+ bool res = env->CallBooleanMethod(media_provider_object_, mid_transform_, j_src.get(),
+ j_dst.get(), transforms, transforms_reason, read_uid,
+ open_uid, transforms_uid);
+
+ if (CheckForJniException(env)) {
+ return false;
+ }
+
+ return res;
+}
+
/*****************************************************************************************/
/******************************** Private member functions *******************************/
/*****************************************************************************************/
@@ -458,7 +542,6 @@
mid = env->GetMethodID(media_provider_class_, actual_method_name.c_str(), signature);
}
if (!mid) {
- // SHOULD NOT HAPPEN!
LOG(FATAL) << "Error caching method: " << method_name << signature;
}
return mid;
diff --git a/jni/MediaProviderWrapper.h b/jni/MediaProviderWrapper.h
index 23c611a..2ad1769 100644
--- a/jni/MediaProviderWrapper.h
+++ b/jni/MediaProviderWrapper.h
@@ -17,6 +17,7 @@
#ifndef MEDIAPROVIDER_FUSE_MEDIAPROVIDERWRAPPER_H_
#define MEDIAPROVIDER_FUSE_MEDIAPROVIDERWRAPPER_H_
+#include <android-base/logging.h>
#include <jni.h>
#include <sys/types.h>
@@ -35,6 +36,48 @@
namespace mediaprovider {
namespace fuse {
+/** Represents file open result from MediaProvider */
+struct FileOpenResult {
+ FileOpenResult(const int status, const int uid, uid_t transforms_uid,
+ const RedactionInfo* redaction_info)
+ : status(status), uid(uid), transforms_uid(transforms_uid), redaction_info(redaction_info) {}
+
+ const int status;
+ const int uid;
+ const uid_t transforms_uid;
+ std::unique_ptr<const RedactionInfo> redaction_info;
+};
+
+/**
+ * Represents transform info for a file, containing the transforms, the transforms completion
+ * status and the ioPath. Provided by MediaProvider.java via a JNI call.
+ */
+struct FileLookupResult {
+ FileLookupResult(int transforms, int transforms_reason, uid_t uid, bool transforms_complete,
+ bool transforms_supported, const std::string& io_path)
+ : transforms(transforms),
+ transforms_reason(transforms_reason),
+ uid(uid),
+ transforms_complete(transforms_complete),
+ transforms_supported(transforms_supported),
+ io_path(io_path) {
+ if (transforms != 0) {
+ CHECK(transforms_supported);
+ }
+ }
+
+ /**
+ * These fields are not to be interpreted, they are determined and populated from MediaProvider
+ * via a JNI call.
+ */
+ const int transforms;
+ const int transforms_reason;
+ const uid_t uid;
+ const bool transforms_complete;
+ const bool transforms_supported;
+ const std::string io_path;
+};
+
/**
* Class that wraps MediaProvider.java and all of the needed JNI calls to make
* interaction with MediaProvider easier.
@@ -48,11 +91,14 @@
* Computes and returns the RedactionInfo for a given file and UID.
*
* @param uid UID of the app requesting the read
- * @param path path of the requested file
+ * @param path path of the requested file that will be used for database operations
+ * @param io_path path of the requested file that will be used for IO
* @return RedactionInfo on success, nullptr on failure to calculate
* redaction ranges (e.g. exception was thrown in Java world)
*/
- std::unique_ptr<RedactionInfo> GetRedactionInfo(const std::string& path, uid_t uid, pid_t tid);
+ std::unique_ptr<RedactionInfo> GetRedactionInfo(const std::string& path,
+ const std::string& io_path, uid_t uid,
+ pid_t tid);
/**
* Inserts a new entry for the given path and UID.
@@ -93,14 +139,26 @@
/**
* Determines if the given UID is allowed to open the file denoted by the given path.
*
- * @param path the path of the file to be opened
+ * Also computes and returns the RedactionInfo for a given file and |uid|
+ *
+ * @param path path of the requested file that will be used for database operations
+ * @param io_path path of the requested file that will be used for IO
* @param uid UID of the calling app
+ * @param tid UID of the calling app
* @param for_write specifies if the file is to be opened for write
- * @return 0 upon success or errno value upon failure.
+ * @param redact specifies whether to attempt redaction
+ * @return FileOpenResult containing status, uid and redaction_info
*/
- int IsOpenAllowed(const std::string& path, uid_t uid, bool for_write);
+ std::unique_ptr<FileOpenResult> OnFileOpen(const std::string& path, const std::string& io_path,
+ uid_t uid, pid_t tid, int transforms_reason,
+ bool for_write, bool redact,
+ bool log_transforms_metrics);
/**
+ * Determines if the given UID is allowed to create a directory with the given path.
+ *
+ * @param path the path of the directory to be created
+ * @param uid UID of the calling app
* @return 0 if it's allowed, or errno error code if operation isn't allowed.
*/
int IsCreatingDirAllowed(const std::string& path, uid_t uid);
@@ -159,6 +217,15 @@
void OnFileCreated(const std::string& path);
/**
+ * Returns FileLookupResult to determine transform info for a path and uid.
+ */
+ std::unique_ptr<FileLookupResult> FileLookup(const std::string& path, uid_t uid, pid_t tid);
+
+ /** Transforms from src to dst file */
+ bool Transform(const std::string& src, const std::string& dst, int transforms,
+ int transforms_reason, uid_t read_uid, uid_t open_uid, uid_t transforms_uid);
+
+ /**
* Determines if to allow FUSE_LOOKUP for uid. Might allow uids that don't belong to the
* MediaProvider user, depending on OEM configuration.
*
@@ -183,13 +250,15 @@
static pthread_key_t gJniEnvKey;
private:
+ jclass file_lookup_result_class_;
+ jclass file_open_result_class_;
jclass media_provider_class_;
jobject media_provider_object_;
/** Cached MediaProvider method IDs **/
- jmethodID mid_get_redaction_ranges_;
jmethodID mid_insert_file_;
jmethodID mid_delete_file_;
- jmethodID mid_is_open_allowed_;
+ jmethodID mid_on_file_open_;
+ jmethodID mid_scan_file_;
jmethodID mid_is_mkdir_or_rmdir_allowed_;
jmethodID mid_is_opendir_allowed_;
jmethodID mid_get_files_in_dir_;
@@ -198,6 +267,20 @@
jmethodID mid_on_file_created_;
jmethodID mid_should_allow_lookup_;
jmethodID mid_is_app_clone_user_;
+ jmethodID mid_transform_;
+ jmethodID mid_file_lookup_;
+ /** Cached FileLookupResult field IDs **/
+ jfieldID fid_file_lookup_transforms_;
+ jfieldID fid_file_lookup_transforms_reason_;
+ jfieldID fid_file_lookup_uid_;
+ jfieldID fid_file_lookup_transforms_complete_;
+ jfieldID fid_file_lookup_transforms_supported_;
+ jfieldID fid_file_lookup_io_path_;
+ /** Cached FileOpenResult field IDs **/
+ jfieldID fid_file_open_status_;
+ jfieldID fid_file_open_uid_;
+ jfieldID fid_file_open_transforms_uid_;
+ jfieldID fid_file_open_redaction_ranges_;
/**
* Auxiliary for caching MediaProvider methods.
diff --git a/jni/com_android_providers_media_FuseDaemon.cpp b/jni/com_android_providers_media_FuseDaemon.cpp
index 3a65696..d67123d 100644
--- a/jni/com_android_providers_media_FuseDaemon.cpp
+++ b/jni/com_android_providers_media_FuseDaemon.cpp
@@ -101,6 +101,25 @@
// TODO(b/145741152): Throw exception
}
+jstring com_android_providers_media_FuseDaemon_get_original_media_format_file_path(
+ JNIEnv* env, jobject self, jlong java_daemon, jint fd) {
+ fuse::FuseDaemon* const daemon = reinterpret_cast<fuse::FuseDaemon*>(java_daemon);
+ const std::string path = daemon->GetOriginalMediaFormatFilePath(fd);
+ return env->NewStringUTF(path.c_str());
+}
+
+void com_android_providers_media_FuseDaemon_initialize_device_id(JNIEnv* env, jobject self,
+ jlong java_daemon,
+ jstring java_path) {
+ fuse::FuseDaemon* const daemon = reinterpret_cast<fuse::FuseDaemon*>(java_daemon);
+ ScopedUtfChars utf_chars_path(env, java_path);
+ if (!utf_chars_path.c_str()) {
+ LOG(WARNING) << "Couldn't initialise FUSE device id";
+ return;
+ }
+ daemon->InitializeDeviceId(utf_chars_path.c_str());
+}
+
bool com_android_providers_media_FuseDaemon_is_fuse_thread(JNIEnv* env, jclass clazz) {
return pthread_getspecific(fuse::MediaProviderWrapper::gJniEnvKey) != nullptr;
}
@@ -120,7 +139,12 @@
reinterpret_cast<void*>(com_android_providers_media_FuseDaemon_is_started)},
{"native_invalidate_fuse_dentry_cache", "(JLjava/lang/String;)V",
reinterpret_cast<void*>(
- com_android_providers_media_FuseDaemon_invalidate_fuse_dentry_cache)}};
+ com_android_providers_media_FuseDaemon_invalidate_fuse_dentry_cache)},
+ {"native_get_original_media_format_file_path", "(JI)Ljava/lang/String;",
+ reinterpret_cast<void*>(
+ com_android_providers_media_FuseDaemon_get_original_media_format_file_path)},
+ {"native_initialize_device_id", "(JLjava/lang/String;)V",
+ reinterpret_cast<void*>(com_android_providers_media_FuseDaemon_initialize_device_id)}};
} // namespace
void register_android_providers_media_FuseDaemon(JavaVM* vm, JNIEnv* env) {
diff --git a/jni/node-inl.h b/jni/node-inl.h
index dfd8141..e531a0a 100644
--- a/jni/node-inl.h
+++ b/jni/node-inl.h
@@ -19,6 +19,8 @@
#include <android-base/logging.h>
+#include <sys/types.h>
+#include <atomic>
#include <cstdint>
#include <limits>
#include <list>
@@ -40,13 +42,23 @@
namespace fuse {
struct handle {
- explicit handle(int fd, const RedactionInfo* ri, bool cached) : fd(fd), ri(ri), cached(cached) {
+ explicit handle(int fd, const RedactionInfo* ri, bool cached, bool passthrough, uid_t uid,
+ uid_t transforms_uid)
+ : fd(fd),
+ ri(ri),
+ cached(cached),
+ passthrough(passthrough),
+ uid(uid),
+ transforms_uid(transforms_uid) {
CHECK(ri != nullptr);
}
const int fd;
const std::unique_ptr<const RedactionInfo> ri;
const bool cached;
+ const bool passthrough;
+ const uid_t uid;
+ const uid_t transforms_uid;
~handle() { close(fd); }
};
@@ -114,21 +126,26 @@
class node {
public:
// Creates a new node with the specified parent, name and lock.
- static node* Create(node* parent, const std::string& name, std::recursive_mutex* lock,
+ static node* Create(node* parent, const std::string& name, const std::string& io_path,
+ bool should_invalidate, bool transforms_complete, const int transforms,
+ const int transforms_reason, std::recursive_mutex* lock, ino_t ino,
NodeTracker* tracker) {
// Place the entire constructor under a critical section to make sure
// node creation, tracking (if enabled) and the addition to a parent are
// atomic.
std::lock_guard<std::recursive_mutex> guard(*lock);
- return new node(parent, name, lock, tracker);
+ return new node(parent, name, io_path, should_invalidate, transforms_complete, transforms,
+ transforms_reason, lock, ino, tracker);
}
// Creates a new root node. Root nodes have no parents by definition
// and their "name" must signify an absolute path.
- static node* CreateRoot(const std::string& path, std::recursive_mutex* lock,
+ static node* CreateRoot(const std::string& path, std::recursive_mutex* lock, ino_t ino,
NodeTracker* tracker) {
std::lock_guard<std::recursive_mutex> guard(*lock);
- node* root = new node(nullptr, path, lock, tracker);
+ node* root = new node(nullptr, path, path, false /* should_invalidate */,
+ true /* transforms_complete */, 0 /* transforms */,
+ 0 /* transforms_reason */, lock, ino, tracker);
// The root always has one extra reference to avoid it being
// accidentally collected.
@@ -174,38 +191,44 @@
// associated with its descendants.
std::string BuildSafePath() const;
- // Looks up a direct descendant of this node by name. If |acquire| is true,
+ // Looks up a direct descendant of this node by case-insensitive |name|. If |acquire| is true,
// also Acquire the node before returning a reference to it.
- node* LookupChildByName(const std::string& name, bool acquire) const {
- std::lock_guard<std::recursive_mutex> guard(*lock_);
-
- // lower_bound will give us the first child with strcasecmp(child->name, name) >=0.
- // For more context see comment on the NodeCompare struct.
- auto start = children_.lower_bound(std::make_pair(name, 0));
- // upper_bound will give us the first child with strcasecmp(child->name, name) > 0
- auto end =
- children_.upper_bound(std::make_pair(name, std::numeric_limits<uintptr_t>::max()));
- for (auto it = start; it != end; it++) {
- node* child = *it;
- if (!child->deleted_) {
+ // |transforms| is an opaque flag that is used to distinguish multiple nodes sharing the same
+ // |name| but requiring different IO transformations as determined by the MediaProvider.
+ node* LookupChildByName(const std::string& name, bool acquire, const int transforms = 0) const {
+ return ForChild(name, [acquire, transforms](node* child) {
+ if (child->transforms_ == transforms) {
if (acquire) {
child->Acquire();
}
- return child;
+ return true;
}
- }
- return nullptr;
+ return false;
+ });
}
- // Marks this node as deleted. It is still associated with its parent, and
- // all open handles etc. to this node are preserved until its refcount goes
+ // Marks this node children as deleted. They are still associated with their parent, and
+ // all open handles etc. to the deleted nodes are preserved until their refcount goes
// to zero.
+ void SetDeletedForChild(const std::string& name) {
+ ForChild(name, [](node* child) {
+ child->SetDeleted();
+ return false;
+ });
+ }
+
void SetDeleted() {
std::lock_guard<std::recursive_mutex> guard(*lock_);
-
deleted_ = true;
}
+ void RenameChild(const std::string& old_name, const std::string& new_name, node* new_parent) {
+ ForChild(old_name, [=](node* child) {
+ child->Rename(new_name, new_parent);
+ return false;
+ });
+ }
+
void Rename(const std::string& name, node* new_parent) {
std::lock_guard<std::recursive_mutex> guard(*lock_);
@@ -252,6 +275,20 @@
return name_;
}
+ const std::string& GetIoPath() const { return io_path_; }
+
+ int GetTransforms() const { return transforms_; }
+
+ int GetTransformsReason() const { return transforms_reason_; }
+
+ bool IsTransformsComplete() const {
+ return transforms_complete_.load(std::memory_order_acquire);
+ }
+
+ void SetTransformsComplete(bool complete) {
+ transforms_complete_.store(complete, std::memory_order_release);
+ }
+
node* GetParent() const {
std::lock_guard<std::recursive_mutex> guard(*lock_);
return parent_;
@@ -282,14 +319,14 @@
return false;
}
- bool HasCaseInsensitiveMatch() const {
+ bool ShouldInvalidate() const {
std::lock_guard<std::recursive_mutex> guard(*lock_);
- return has_case_insensitive_match_;
+ return should_invalidate_;
}
- void SetCaseInsensitiveMatch() {
+ void SetShouldInvalidate() {
std::lock_guard<std::recursive_mutex> guard(*lock_);
- has_case_insensitive_match_ = true;
+ should_invalidate_ = true;
}
bool HasRedactedCache() const {
@@ -324,15 +361,25 @@
// through the hierarchy exists.
static const node* LookupAbsolutePath(const node* root, const std::string& absolute_path);
+ // Looks up for the node with the given ino rooted at |root|, or nullptr if no such node exists.
+ static const node* LookupInode(const node* root, ino_t ino);
+
private:
- node(node* parent, const std::string& name, std::recursive_mutex* lock, NodeTracker* tracker)
+ node(node* parent, const std::string& name, const std::string& io_path,
+ const bool should_invalidate, const bool transforms_complete, const int transforms,
+ const int transforms_reason, std::recursive_mutex* lock, ino_t ino, NodeTracker* tracker)
: name_(name),
+ io_path_(io_path),
+ transforms_complete_(transforms_complete),
+ transforms_(transforms),
+ transforms_reason_(transforms_reason),
refcount_(0),
parent_(nullptr),
has_redacted_cache_(false),
- has_case_insensitive_match_(false),
+ should_invalidate_(should_invalidate),
deleted_(false),
lock_(lock),
+ ino_(ino),
tracker_(tracker) {
tracker_->NodeCreated(this);
Acquire();
@@ -341,6 +388,10 @@
if (parent != nullptr) {
AddToParent(parent);
}
+ // If the node requires transforms, we MUST never cache it in the VFS
+ if (transforms) {
+ CHECK(should_invalidate_);
+ }
}
// Acquires a reference to a node. This maps to the "lookup count" specified
@@ -381,6 +432,32 @@
}
}
+ // Finds *all* non-deleted nodes matching |name| and runs the function |callback| on each
+ // node until |callback| returns true.
+ // When |callback| returns true, the matched node is returned
+ node* ForChild(const std::string& name, const std::function<bool(node*)>& callback) const {
+ std::lock_guard<std::recursive_mutex> guard(*lock_);
+
+ // lower_bound will give us the first child with strcasecmp(child->name, name) >=0.
+ // For more context see comment on the NodeCompare struct.
+ auto start = children_.lower_bound(std::make_pair(name, 0));
+ // upper_bound will give us the first child with strcasecmp(child->name, name) > 0
+ auto end =
+ children_.upper_bound(std::make_pair(name, std::numeric_limits<uintptr_t>::max()));
+
+ // Make a copy of the matches because calling callback might modify the list which will
+ // cause issues while iterating over them.
+ std::vector<node*> children(start, end);
+
+ for (node* child : children) {
+ if (!child->deleted_ && callback(child)) {
+ return child;
+ }
+ }
+
+ return nullptr;
+ }
+
// A custom heterogeneous comparator used for set of this node's children_ to speed up child
// node by name lookups.
//
@@ -427,6 +504,20 @@
// The name of this node. Non-const because it can change during renames.
std::string name_;
+ // Filesystem path that will be used for IO (if it is non-empty) instead of node->BuildPath
+ const std::string io_path_;
+ // Whether any transforms required on |io_path_| are complete.
+ // If false, might need to call a node transform function with |transforms| below
+ std::atomic_bool transforms_complete_;
+ // Opaque flags that determines the 'required' transforms to perform on node
+ // before IO. These flags should not be interpreted in native but should be passed to the
+ // MediaProvider as part of a transform function and if successful, |transforms_complete_|
+ // should be set to true
+ const int transforms_;
+ // Opaque value indicating the reason why transforms are required.
+ // This value should not be interpreted in native but should be passed to the MediaProvider
+ // as part of a transform function
+ const int transforms_reason_;
// The reference count for this node. Guarded by |lock_|.
uint32_t refcount_;
// Set of children of this node. All of them contain a back reference
@@ -439,9 +530,11 @@
// List of directory handles associated with this node. Guarded by |lock_|.
std::vector<std::unique_ptr<dirhandle>> dirhandles_;
bool has_redacted_cache_;
- bool has_case_insensitive_match_;
+ bool should_invalidate_;
bool deleted_;
std::recursive_mutex* lock_;
+ // Inode number of the file represented by this node.
+ const ino_t ino_;
NodeTracker* const tracker_;
diff --git a/jni/node.cpp b/jni/node.cpp
index e17a9e8..31e4970 100644
--- a/jni/node.cpp
+++ b/jni/node.cpp
@@ -93,6 +93,24 @@
return node;
}
+const node* node::LookupInode(const node* root, ino_t ino) {
+ CHECK(root);
+
+ std::lock_guard<std::recursive_mutex> guard(*root->lock_);
+
+ if ((root->ino_ == ino) && !root->deleted_ && !(root->handles_.empty())) {
+ return root;
+ }
+
+ for (node* child : root->children_) {
+ const node* node = LookupInode(child, ino);
+ if (node) {
+ return node;
+ }
+ }
+ return nullptr;
+}
+
void node::DeleteTree(node* tree) {
std::lock_guard<std::recursive_mutex> guard(*tree->lock_);
diff --git a/jni/node_test.cpp b/jni/node_test.cpp
index 357cea8..e6870f8 100644
--- a/jni/node_test.cpp
+++ b/jni/node_test.cpp
@@ -31,8 +31,15 @@
typedef std::unique_ptr<node, decltype(&NodeTest::destroy)> unique_node_ptr;
- unique_node_ptr CreateNode(node* parent, const std::string& path) {
- return unique_node_ptr(node::Create(parent, path, &lock_, &tracker_), &NodeTest::destroy);
+ unique_node_ptr CreateNode(node* parent, const std::string& path, const int transforms = 0) {
+ return unique_node_ptr(
+ node::Create(parent, path, "", true, true, transforms, 0, &lock_, 0, &tracker_),
+ &NodeTest::destroy);
+ }
+
+ static class node* ForChild(class node* node, const std::string& name,
+ const std::function<bool(class node*)>& callback) {
+ return node->ForChild(name, callback);
}
// Expose NodeCompare for testing.
@@ -61,7 +68,7 @@
}
TEST_F(NodeTest, TestRelease) {
- node* node = node::Create(nullptr, "/path", &lock_, &tracker_);
+ node* node = node::Create(nullptr, "/path", "", false, true, 0, 0, &lock_, 0, &tracker_);
acquire(node);
acquire(node);
ASSERT_EQ(3, GetRefCount(node));
@@ -77,7 +84,7 @@
ASSERT_TRUE(node->Release(2));
}
-TEST_F(NodeTest, TestRenameWithName) {
+TEST_F(NodeTest, TestRenameName) {
unique_node_ptr parent = CreateNode(nullptr, "/path");
unique_node_ptr child = CreateNode(parent.get(), "subdir");
@@ -94,7 +101,7 @@
ASSERT_EQ(1, GetRefCount(child.get()));
}
-TEST_F(NodeTest, TestRenameWithParent) {
+TEST_F(NodeTest, TestRenameParent) {
unique_node_ptr parent1 = CreateNode(nullptr, "/path1");
unique_node_ptr parent2 = CreateNode(nullptr, "/path2");
@@ -113,7 +120,7 @@
ASSERT_EQ(1, GetRefCount(child.get()));
}
-TEST_F(NodeTest, TestRenameWithNameAndParent) {
+TEST_F(NodeTest, TestRenameNameAndParent) {
unique_node_ptr parent1 = CreateNode(nullptr, "/path1");
unique_node_ptr parent2 = CreateNode(nullptr, "/path2");
@@ -133,6 +140,101 @@
ASSERT_EQ(1, GetRefCount(child.get()));
}
+TEST_F(NodeTest, TestRenameNameForChild) {
+ unique_node_ptr parent = CreateNode(nullptr, "/path");
+
+ unique_node_ptr child0 = CreateNode(parent.get(), "subdir", 0 /* transforms */);
+ unique_node_ptr child1 = CreateNode(parent.get(), "subdir", 1 /* transforms */);
+ ASSERT_EQ(3, GetRefCount(parent.get()));
+ ASSERT_EQ(child0.get(),
+ parent->LookupChildByName("subdir", false /* acquire */, 0 /* transforms */));
+ ASSERT_EQ(child1.get(),
+ parent->LookupChildByName("subdir", false /* acquire */, 1 /* transforms */));
+
+ parent->RenameChild("subdir", "subdir_new", parent.get());
+
+ ASSERT_EQ(3, GetRefCount(parent.get()));
+ ASSERT_EQ(nullptr,
+ parent->LookupChildByName("subdir", false /* acquire */, 0 /* transforms */));
+ ASSERT_EQ(nullptr,
+ parent->LookupChildByName("subdir", false /* acquire */, 1 /* transforms */));
+ ASSERT_EQ(child0.get(),
+ parent->LookupChildByName("subdir_new", false /* acquire */, 0 /* transforms */));
+ ASSERT_EQ(child1.get(),
+ parent->LookupChildByName("subdir_new", false /* acquire */, 1 /* transforms */));
+
+ ASSERT_EQ("/path/subdir_new", child0->BuildPath());
+ ASSERT_EQ("/path/subdir_new", child1->BuildPath());
+ ASSERT_EQ(1, GetRefCount(child0.get()));
+ ASSERT_EQ(1, GetRefCount(child1.get()));
+}
+
+TEST_F(NodeTest, TestRenameParentForChild) {
+ unique_node_ptr parent1 = CreateNode(nullptr, "/path1");
+ unique_node_ptr parent2 = CreateNode(nullptr, "/path2");
+
+ unique_node_ptr child0 = CreateNode(parent1.get(), "subdir", 0 /* transforms */);
+ unique_node_ptr child1 = CreateNode(parent1.get(), "subdir", 1 /* transforms */);
+ ASSERT_EQ(3, GetRefCount(parent1.get()));
+ ASSERT_EQ(child0.get(),
+ parent1->LookupChildByName("subdir", false /* acquire */, 0 /* transforms */));
+ ASSERT_EQ(child1.get(),
+ parent1->LookupChildByName("subdir", false /* acquire */, 1 /* transforms */));
+
+ parent1->RenameChild("subdir", "subdir", parent2.get());
+ ASSERT_EQ(1, GetRefCount(parent1.get()));
+ ASSERT_EQ(nullptr,
+ parent1->LookupChildByName("subdir", false /* acquire */, 0 /* transforms */));
+ ASSERT_EQ(nullptr,
+ parent1->LookupChildByName("subdir", false /* acquire */, 1 /* transforms */));
+
+ ASSERT_EQ(3, GetRefCount(parent2.get()));
+ ASSERT_EQ(child0.get(),
+ parent2->LookupChildByName("subdir", false /* acquire */, 0 /* transforms */));
+ ASSERT_EQ(child1.get(),
+ parent2->LookupChildByName("subdir", false /* acquire */, 1 /* transforms */));
+
+ ASSERT_EQ("/path2/subdir", child0->BuildPath());
+ ASSERT_EQ("/path2/subdir", child1->BuildPath());
+ ASSERT_EQ(1, GetRefCount(child0.get()));
+ ASSERT_EQ(1, GetRefCount(child1.get()));
+}
+
+TEST_F(NodeTest, TestRenameNameAndParentForChild) {
+ unique_node_ptr parent1 = CreateNode(nullptr, "/path1");
+ unique_node_ptr parent2 = CreateNode(nullptr, "/path2");
+
+ unique_node_ptr child0 = CreateNode(parent1.get(), "subdir", 0 /* transforms */);
+ unique_node_ptr child1 = CreateNode(parent1.get(), "subdir", 1 /* transforms */);
+ ASSERT_EQ(3, GetRefCount(parent1.get()));
+ ASSERT_EQ(child0.get(),
+ parent1->LookupChildByName("subdir", false /* acquire */, 0 /* transforms */));
+ ASSERT_EQ(child1.get(),
+ parent1->LookupChildByName("subdir", false /* acquire */, 1 /* transforms */));
+
+ parent1->RenameChild("subdir", "subdir_new", parent2.get());
+ ASSERT_EQ(1, GetRefCount(parent1.get()));
+ ASSERT_EQ(nullptr,
+ parent1->LookupChildByName("subdir", false /* acquire */, 0 /* transforms */));
+ ASSERT_EQ(nullptr,
+ parent1->LookupChildByName("subdir_new", false /* acquire */, 0 /* transforms */));
+ ASSERT_EQ(nullptr,
+ parent1->LookupChildByName("subdir", false /* acquire */, 1 /* transforms */));
+ ASSERT_EQ(nullptr,
+ parent1->LookupChildByName("subdir_new", false /* acquire */, 1 /* transforms */));
+
+ ASSERT_EQ(3, GetRefCount(parent2.get()));
+ ASSERT_EQ(nullptr,
+ parent1->LookupChildByName("subdir_new", false /* acquire */, 0 /* transforms */));
+ ASSERT_EQ(nullptr,
+ parent1->LookupChildByName("subdir_new", false /* acquire */, 1 /* transforms */));
+
+ ASSERT_EQ("/path2/subdir_new", child0->BuildPath());
+ ASSERT_EQ("/path2/subdir_new", child1->BuildPath());
+ ASSERT_EQ(1, GetRefCount(child0.get()));
+ ASSERT_EQ(1, GetRefCount(child1.get()));
+}
+
TEST_F(NodeTest, TestBuildPath) {
unique_node_ptr parent = CreateNode(nullptr, "/path");
ASSERT_EQ("/path", parent->BuildPath());
@@ -156,14 +258,30 @@
ASSERT_EQ(nullptr, parent->LookupChildByName("subdir", false /* acquire */));
}
+TEST_F(NodeTest, TestSetDeletedForChild) {
+ unique_node_ptr parent = CreateNode(nullptr, "/path");
+ unique_node_ptr child0 = CreateNode(parent.get(), "subdir", 0 /* transforms */);
+ unique_node_ptr child1 = CreateNode(parent.get(), "subdir", 1 /* transforms */);
+
+ ASSERT_EQ(child0.get(),
+ parent->LookupChildByName("subdir", false /* acquire */, 0 /* transforms */));
+ ASSERT_EQ(child1.get(),
+ parent->LookupChildByName("subdir", false /* acquire */, 1 /* transforms */));
+ parent->SetDeletedForChild("subdir");
+ ASSERT_EQ(nullptr,
+ parent->LookupChildByName("subdir", false /* acquire */, 0 /* transforms */));
+ ASSERT_EQ(nullptr,
+ parent->LookupChildByName("subdir", false /* acquire */, 1 /* transforms */));
+}
+
TEST_F(NodeTest, DeleteTree) {
unique_node_ptr parent = CreateNode(nullptr, "/path");
// This is the tree that we intend to delete.
- node* child = node::Create(parent.get(), "subdir", &lock_, &tracker_);
- node::Create(child, "s1", &lock_, &tracker_);
- node* subchild2 = node::Create(child, "s2", &lock_, &tracker_);
- node::Create(subchild2, "sc2", &lock_, &tracker_);
+ node* child = node::Create(parent.get(), "subdir", "", false, true, 0, 0, &lock_, 0, &tracker_);
+ node::Create(child, "s1", "", false, true, 0, 0, &lock_, 0, &tracker_);
+ node* subchild2 = node::Create(child, "s2", "", false, true, 0, 0, &lock_, 0, &tracker_);
+ node::Create(subchild2, "sc2", "", false, true, 0, 0, &lock_, 0, &tracker_);
ASSERT_EQ(child, parent->LookupChildByName("subdir", false /* acquire */));
node::DeleteTree(child);
@@ -178,6 +296,20 @@
ASSERT_EQ(nullptr, parent->LookupChildByName("", false /* acquire */));
}
+TEST_F(NodeTest, LookupChildByName_transforms) {
+ unique_node_ptr parent = CreateNode(nullptr, "/path");
+ unique_node_ptr child0 = CreateNode(parent.get(), "subdir", 0 /* transforms */);
+ unique_node_ptr child1 = CreateNode(parent.get(), "subdir", 1 /* transforms */);
+
+ ASSERT_EQ(child0.get(), parent->LookupChildByName("subdir", false /* acquire */));
+ ASSERT_EQ(child0.get(),
+ parent->LookupChildByName("subdir", false /* acquire */, 0 /* transforms */));
+ ASSERT_EQ(child1.get(),
+ parent->LookupChildByName("subdir", false /* acquire */, 1 /* transforms */));
+ ASSERT_EQ(nullptr,
+ parent->LookupChildByName("subdir", false /* acquire */, 2 /* transforms */));
+}
+
TEST_F(NodeTest, LookupChildByName_refcounts) {
unique_node_ptr parent = CreateNode(nullptr, "/path");
unique_node_ptr child = CreateNode(parent.get(), "subdir");
@@ -217,7 +349,8 @@
TEST_F(NodeTest, AddDestroyHandle) {
unique_node_ptr node = CreateNode(nullptr, "/path");
- handle* h = new handle(-1, new mediaprovider::fuse::RedactionInfo, true /* cached */);
+ handle* h = new handle(-1, new mediaprovider::fuse::RedactionInfo, true /* cached */,
+ false /* passthrough */, 0 /* uid */, 0 /* transforms_uid */);
node->AddHandle(h);
ASSERT_TRUE(node->HasCachedHandle());
@@ -228,8 +361,9 @@
// the node in question.
EXPECT_DEATH(node->DestroyHandle(h), "");
EXPECT_DEATH(node->DestroyHandle(nullptr), "");
- std::unique_ptr<handle> h2(
- new handle(-1, new mediaprovider::fuse::RedactionInfo, true /* cached */));
+ std::unique_ptr<handle> h2(new handle(-1, new mediaprovider::fuse::RedactionInfo,
+ true /* cached */, false /* passthrough */, 0 /* uid */,
+ 0 /* transforms_uid */));
EXPECT_DEATH(node->DestroyHandle(h2.get()), "");
}
@@ -318,3 +452,44 @@
test_fn("bAr", bar1.get(), bar2.get());
test_fn("BaZ", baz1.get(), baz2.get());
}
+
+TEST_F(NodeTest, ForChild) {
+ unique_node_ptr parent = CreateNode(nullptr, "/path");
+ unique_node_ptr foo1 = CreateNode(parent.get(), "FoO");
+ unique_node_ptr foo2 = CreateNode(parent.get(), "fOo");
+ unique_node_ptr foo3 = CreateNode(parent.get(), "foo");
+ foo3->SetDeleted();
+
+ std::vector<node*> match_all;
+ auto test_fn_match_all = [&](node* child) {
+ match_all.push_back(child);
+ return false;
+ };
+
+ std::vector<node*> match_first;
+ auto test_fn_match_first = [&](node* child) {
+ match_first.push_back(child);
+ return true;
+ };
+
+ std::vector<node*> match_none;
+ auto test_fn_match_none = [&](node* child) {
+ match_none.push_back(child);
+ return false;
+ };
+
+ node* node_all = ForChild(parent.get(), "foo", test_fn_match_all);
+ ASSERT_EQ(nullptr, node_all);
+ ASSERT_EQ(2, match_all.size());
+ ASSERT_EQ(std::min(foo1.get(), foo2.get()), match_all[0]);
+ ASSERT_EQ(std::max(foo1.get(), foo2.get()), match_all[1]);
+
+ node* node_first = ForChild(parent.get(), "foo", test_fn_match_first);
+ ASSERT_EQ(std::min(foo1.get(), foo2.get()), node_first);
+ ASSERT_EQ(1, match_first.size());
+ ASSERT_EQ(std::min(foo1.get(), foo2.get()), match_first[0]);
+
+ node* node_none = ForChild(parent.get(), "bar", test_fn_match_none);
+ ASSERT_EQ(nullptr, node_none);
+ ASSERT_TRUE(match_none.empty());
+}
diff --git a/legacy/Android.bp b/legacy/Android.bp
index 203ee5a..dd9e5f8 100644
--- a/legacy/Android.bp
+++ b/legacy/Android.bp
@@ -1,4 +1,13 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "packages_providers_MediaProvider_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["packages_providers_MediaProvider_license"],
+}
+
android_app {
name: "MediaProviderLegacy",
manifest: "AndroidManifest.xml",
@@ -7,6 +16,7 @@
"androidx.appcompat_appcompat",
"androidx.core_core",
"guava",
+ "modules-utils-build",
],
libs: ["app-compat-annotations"],
@@ -17,7 +27,7 @@
":mediaprovider-database-sources",
],
+ platform_apis: true,
certificate: "media",
privileged: true,
- sdk_version: "system_current",
}
diff --git a/lint-baseline.xml b/lint-baseline.xml
new file mode 100644
index 0000000..5f39c57
--- /dev/null
+++ b/lint-baseline.xml
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 31 (current min is 30): `android.os.storage.StorageVolume#getStorageUuid`"
+ errorLine1=" mTranscodeVolumeUuid = vol.getStorageUuid();"
+ errorLine2=" ~~~~~~~~~~~~~~">
+ <location
+ file="packages/providers/MediaProvider/src/com/android/providers/media/TranscodeHelper.java"
+ line="311"
+ column="44"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 31 (current min is 30): `android.content.pm.PackageManager#getProperty`"
+ errorLine1=" Property mediaCapProperty = mPackageManager.getProperty("
+ errorLine2=" ~~~~~~~~~~~">
+ <location
+ file="packages/providers/MediaProvider/src/com/android/providers/media/TranscodeHelper.java"
+ line="827"
+ column="57"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 31 (current min is 30): `android.content.pm.PackageManager.Property#getResourceId`"
+ errorLine1=" .getXml(mediaCapProperty.getResourceId());"
+ errorLine2=" ~~~~~~~~~~~~~">
+ <location
+ file="packages/providers/MediaProvider/src/com/android/providers/media/TranscodeHelper.java"
+ line="830"
+ column="46"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 31 (current min is 30): `android.media.ApplicationMediaCapabilities#createFromXml`"
+ errorLine1=" ApplicationMediaCapabilities capability = ApplicationMediaCapabilities.createFromXml("
+ errorLine2=" ~~~~~~~~~~~~~">
+ <location
+ file="packages/providers/MediaProvider/src/com/android/providers/media/TranscodeHelper.java"
+ line="831"
+ column="84"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 31 (current min is 30): `android.media.ApplicationMediaCapabilities#isFormatSpecified`"
+ errorLine1=" if (capability.isFormatSpecified(MediaFormat.MIMETYPE_VIDEO_HEVC)) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/providers/MediaProvider/src/com/android/providers/media/TranscodeHelper.java"
+ line="852"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 31 (current min is 30): `android.media.ApplicationMediaCapabilities#isVideoMimeTypeSupported`"
+ errorLine1=" if (capability.isVideoMimeTypeSupported(MediaFormat.MIMETYPE_VIDEO_HEVC)) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/providers/MediaProvider/src/com/android/providers/media/TranscodeHelper.java"
+ line="853"
+ column="28"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 31 (current min is 30): `android.media.ApplicationMediaCapabilities#isFormatSpecified`"
+ errorLine1=" if (capability.isFormatSpecified(MediaFeature.HdrType.HDR10)) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/providers/MediaProvider/src/com/android/providers/media/TranscodeHelper.java"
+ line="861"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 31 (current min is 30): `android.media.ApplicationMediaCapabilities#isHdrTypeSupported`"
+ errorLine1=" if (capability.isHdrTypeSupported(MediaFeature.HdrType.HDR10)) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/providers/MediaProvider/src/com/android/providers/media/TranscodeHelper.java"
+ line="862"
+ column="28"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 31 (current min is 30): `android.media.ApplicationMediaCapabilities#isFormatSpecified`"
+ errorLine1=" if (capability.isFormatSpecified(MediaFeature.HdrType.HDR10_PLUS)) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/providers/MediaProvider/src/com/android/providers/media/TranscodeHelper.java"
+ line="869"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 31 (current min is 30): `android.media.ApplicationMediaCapabilities#isHdrTypeSupported`"
+ errorLine1=" if (capability.isHdrTypeSupported(MediaFeature.HdrType.HDR10_PLUS)) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/providers/MediaProvider/src/com/android/providers/media/TranscodeHelper.java"
+ line="870"
+ column="28"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 31 (current min is 30): `android.media.ApplicationMediaCapabilities#isFormatSpecified`"
+ errorLine1=" if (capability.isFormatSpecified(MediaFeature.HdrType.HLG)) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/providers/MediaProvider/src/com/android/providers/media/TranscodeHelper.java"
+ line="877"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 31 (current min is 30): `android.media.ApplicationMediaCapabilities#isHdrTypeSupported`"
+ errorLine1=" if (capability.isHdrTypeSupported(MediaFeature.HdrType.HLG)) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/providers/MediaProvider/src/com/android/providers/media/TranscodeHelper.java"
+ line="878"
+ column="28"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 31 (current min is 30): `android.media.ApplicationMediaCapabilities#isFormatSpecified`"
+ errorLine1=" if (capability.isFormatSpecified(MediaFeature.HdrType.DOLBY_VISION)) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/providers/MediaProvider/src/com/android/providers/media/TranscodeHelper.java"
+ line="885"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 31 (current min is 30): `android.media.ApplicationMediaCapabilities#isHdrTypeSupported`"
+ errorLine1=" if (capability.isHdrTypeSupported(MediaFeature.HdrType.DOLBY_VISION)) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/providers/MediaProvider/src/com/android/providers/media/TranscodeHelper.java"
+ line="886"
+ column="28"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 31 (current min is 30): `android.media.ApplicationMediaCapabilities.Builder#build`"
+ errorLine1=" new ApplicationMediaCapabilities.Builder().build();"
+ errorLine2=" ~~~~~">
+ <location
+ file="packages/providers/MediaProvider/src/com/android/providers/media/TranscodeHelper.java"
+ line="1079"
+ column="68"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 31 (current min is 30): `new android.media.ApplicationMediaCapabilities.Builder`"
+ errorLine1=" new ApplicationMediaCapabilities.Builder().build();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/providers/MediaProvider/src/com/android/providers/media/TranscodeHelper.java"
+ line="1079"
+ column="25"/>
+ </issue>
+
+</issues>
diff --git a/logging.sh b/logging.sh
index fd2a3a5..c1143ce 100755
--- a/logging.sh
+++ b/logging.sh
@@ -6,6 +6,7 @@
then
adb shell setprop log.tag.MediaProvider VERBOSE
adb shell setprop log.tag.ModernMediaScanner VERBOSE
+ adb shell setprop log.tag.TranscodeHelper VERBOSE
adb shell setprop log.tag.FuseDaemon DEBUG
adb shell setprop log.tag.libfuse DEBUG
else
@@ -20,6 +21,7 @@
adb shell setprop log.tag.SQLiteQueryBuilder VERBOSE
adb shell setprop log.tag.FuseDaemon VERBOSE
adb shell setprop log.tag.libfuse VERBOSE
+ adb shell setprop log.tag.TranscodeHelper VERBOSE
adb shell setprop persist.sys.fuse.log true
else
adb shell setprop log.tag.SQLiteQueryBuilder INFO
diff --git a/preinstalled-packages-com.android.providers.media.module.xml b/preinstalled-packages-com.android.providers.media.module.xml
new file mode 100644
index 0000000..fd31162
--- /dev/null
+++ b/preinstalled-packages-com.android.providers.media.module.xml
@@ -0,0 +1,23 @@
+<!--
+ ~ 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.
+ -->
+<config>
+ <install-in-user-type package="com.android.providers.media.module">
+ <install-in user-type="SYSTEM"/>
+ <install-in user-type="FULL"/>
+ <install-in user-type="PROFILE"/>
+ <do-not-install-in user-type="android.os.usertype.profile.CLONE"/>
+ </install-in-user-type>
+</config>
\ No newline at end of file
diff --git a/res/layout/permission_body.xml b/res/layout/permission_body.xml
index 0fb4ece..7c74065 100644
--- a/res/layout/permission_body.xml
+++ b/res/layout/permission_body.xml
@@ -97,11 +97,5 @@
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:visibility="gone" />
- <TextView
- android:id="@+id/message"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="12dp"
- android:visibility="gone" />
</LinearLayout>
</LinearLayout>
diff --git a/res/layout/photo_picker.xml b/res/layout/photo_picker.xml
new file mode 100644
index 0000000..073a8bd
--- /dev/null
+++ b/res/layout/photo_picker.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".MainActivity">
+
+ <Button
+ android:id="@+id/button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Give up"
+ />
+
+ <ListView
+ android:id="@+id/names_list"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ />
+
+</LinearLayout>
diff --git a/res/raw/transcode_compat_manifest b/res/raw/transcode_compat_manifest
new file mode 100644
index 0000000..daac909
--- /dev/null
+++ b/res/raw/transcode_compat_manifest
@@ -0,0 +1,3 @@
+com.yelp.android,0
+com.yy.biu,0
+com.groupme.android,0
\ No newline at end of file
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 09a1296..46d36bf 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">Laat <xliff:g id="APP_NAME_1">^1</xliff:g> toe om <xliff:g id="COUNT">^2</xliff:g> oudiolêers te wysig?</item>
<item quantity="one">Laat <xliff:g id="APP_NAME_0">^1</xliff:g> toe om hierdie oudiolêer te wysig?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other">Wysig tans <xliff:g id="COUNT">^1</xliff:g> oudiolêers …</item>
+ <item quantity="one">Wysig tans oudiolêer …</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">Laat <xliff:g id="APP_NAME_1">^1</xliff:g> toe om <xliff:g id="COUNT">^2</xliff:g> video\'s te wysig?</item>
<item quantity="one">Laat <xliff:g id="APP_NAME_0">^1</xliff:g> toe om hierdie video te wysig?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other">Wysig tans <xliff:g id="COUNT">^1</xliff:g> video\'s …</item>
+ <item quantity="one">Wysig tans video …</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">Laat <xliff:g id="APP_NAME_1">^1</xliff:g> toe om <xliff:g id="COUNT">^2</xliff:g> foto\'s te wysig?</item>
<item quantity="one">Laat <xliff:g id="APP_NAME_0">^1</xliff:g> toe om hierdie foto te wysig?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other">Wysig tans <xliff:g id="COUNT">^1</xliff:g> foto\'s …</item>
+ <item quantity="one">Wysig tans foto …</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">Laat <xliff:g id="APP_NAME_1">^1</xliff:g> toe om <xliff:g id="COUNT">^2</xliff:g> items te wysig?</item>
<item quantity="one">Laat <xliff:g id="APP_NAME_0">^1</xliff:g> toe om hierdie item te wysig?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other">Wysig tans <xliff:g id="COUNT">^1</xliff:g> items …</item>
+ <item quantity="one">Wysig tans item …</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">Laat <xliff:g id="APP_NAME_1">^1</xliff:g> toe om <xliff:g id="COUNT">^2</xliff:g> oudiolêers na die asblik toe te skuif?</item>
<item quantity="one">Laat <xliff:g id="APP_NAME_0">^1</xliff:g> toe om hierdie oudiolêer na die asblik toe te skuif?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other">Skuif tans <xliff:g id="COUNT">^1</xliff:g> oudiolêers na asblik …</item>
+ <item quantity="one">Skuif tans oudiolêer na asblik …</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">Laat <xliff:g id="APP_NAME_1">^1</xliff:g> toe om <xliff:g id="COUNT">^2</xliff:g> video\'s na die asblik toe te skuif?</item>
<item quantity="one">Laat <xliff:g id="APP_NAME_0">^1</xliff:g> toe om hierdie video na die asblik toe skuif?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other">Skuif tans <xliff:g id="COUNT">^1</xliff:g> video\'s na asblik …</item>
+ <item quantity="one">Skuif tans video na asblik …</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">Laat <xliff:g id="APP_NAME_1">^1</xliff:g> toe om <xliff:g id="COUNT">^2</xliff:g> foto\'s na die asblik toe te skuif?</item>
<item quantity="one">Laat <xliff:g id="APP_NAME_0">^1</xliff:g> toe om hierdie foto na die asblik toe skuif?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other">Skuif tans <xliff:g id="COUNT">^1</xliff:g> foto\'s na asblik …</item>
+ <item quantity="one">Skuif tans foto na asblik …</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">Laat <xliff:g id="APP_NAME_1">^1</xliff:g> toe om <xliff:g id="COUNT">^2</xliff:g> items na die asblik toe te skuif?</item>
<item quantity="one">Laat <xliff:g id="APP_NAME_0">^1</xliff:g> toe om hierdie item na die asblik toe skuif?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other">Skuif tans <xliff:g id="COUNT">^1</xliff:g> items na asblik …</item>
+ <item quantity="one">Skuif tans item na asblik …</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">Laat <xliff:g id="APP_NAME_1">^1</xliff:g> toe om <xliff:g id="COUNT">^2</xliff:g> oudiolêers uit die asblik uit te skuif?</item>
<item quantity="one">Laat <xliff:g id="APP_NAME_0">^1</xliff:g> toe om hierdie oudiolêer uit die asblik uit te skuif?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other">Skuif tans <xliff:g id="COUNT">^1</xliff:g> oudiolêers uit die asblik uit …</item>
+ <item quantity="one">Skuif tans oudiolêer uit die asblik uit …</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">Laat <xliff:g id="APP_NAME_1">^1</xliff:g> toe om <xliff:g id="COUNT">^2</xliff:g> video\'s uit die asblik uit te skuif?</item>
<item quantity="one">Laat <xliff:g id="APP_NAME_0">^1</xliff:g> toe om hierdie video uit die asblik uit te skuif?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other">Skuif tans <xliff:g id="COUNT">^1</xliff:g> video\'s uit die asblik uit …</item>
+ <item quantity="one">Skuif tans video uit die asblik uit …</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">Laat <xliff:g id="APP_NAME_1">^1</xliff:g> toe om <xliff:g id="COUNT">^2</xliff:g> foto\'s uit die asblik uit te skuif?</item>
<item quantity="one">Laat <xliff:g id="APP_NAME_0">^1</xliff:g> toe om hierdie foto uit die asblik uit te skuif?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other">Skuif tans <xliff:g id="COUNT">^1</xliff:g> foto\'s uit die asblik uit …</item>
+ <item quantity="one">Skuif tans foto uit die asblik uit …</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">Laat <xliff:g id="APP_NAME_1">^1</xliff:g> toe om <xliff:g id="COUNT">^2</xliff:g> items uit die asblik uit te skuif?</item>
<item quantity="one">Laat <xliff:g id="APP_NAME_0">^1</xliff:g> toe om hierdie item uit die asblik uit te skuif?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other">Skuif tans <xliff:g id="COUNT">^1</xliff:g> items uit die asblik uit …</item>
+ <item quantity="one">Skuif tans item uit die asblik uit …</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">Laat <xliff:g id="APP_NAME_1">^1</xliff:g> toe om <xliff:g id="COUNT">^2</xliff:g> oudiolêers uit te vee?</item>
<item quantity="one">Laat <xliff:g id="APP_NAME_0">^1</xliff:g> toe om hierdie oudiolêer uit te vee?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other">Vee tans <xliff:g id="COUNT">^1</xliff:g> oudiolêers uit …</item>
+ <item quantity="one">Vee tans oudiolêer uit</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">Laat <xliff:g id="APP_NAME_1">^1</xliff:g> toe om <xliff:g id="COUNT">^2</xliff:g> video\'s uit te vee?</item>
<item quantity="one">Laat <xliff:g id="APP_NAME_0">^1</xliff:g> toe om hierdie video uit te vee?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other">Vee tans <xliff:g id="COUNT">^1</xliff:g> video\'s uit …</item>
+ <item quantity="one">Vee tans video uit …</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">Laat <xliff:g id="APP_NAME_1">^1</xliff:g> toe om <xliff:g id="COUNT">^2</xliff:g> foto\'s uit te vee?</item>
<item quantity="one">Laat <xliff:g id="APP_NAME_0">^1</xliff:g> toe om hierdie foto uit te vee?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other">Vee tans <xliff:g id="COUNT">^1</xliff:g> foto\'s uit …</item>
+ <item quantity="one">Vee tans foto uit …</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">Laat <xliff:g id="APP_NAME_1">^1</xliff:g> toe om <xliff:g id="COUNT">^2</xliff:g> items uit te vee?</item>
<item quantity="one">Laat <xliff:g id="APP_NAME_0">^1</xliff:g> toe om hierdie item uit te vee?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other">Vee tans <xliff:g id="COUNT">^1</xliff:g> items uit …</item>
+ <item quantity="one">Vee tans item uit …</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> kan nie medialêers verwerk nie"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Mediaverwerking is gekanselleer"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Mediaverwerkingfout"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Mediaverwerkingsukses"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Mediaverwerking het begin"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Verwerk media …"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Kanselleer"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Wag"</string>
</resources>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 1a62bf5..fb69fe1 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -47,64 +47,136 @@
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ኦዲዮ ፋይሎችን እንዲቀይር ይፈቀድለት?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ኦዲዮ ፋይሎችን እንዲቀይር ይፈቀድለት?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> የኦዲዮ ፋይሎችን በመቀየር ላይ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> የኦዲዮ ፋይሎችን በመቀየር ላይ…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ቪዲዮዎችን እንዲቀይር ይፈቀድለት?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ቪዲዮዎችን እንዲቀይር ይፈቀድለት?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ቪዲዮዎችን በመቀየር ላይ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ቪዲዮዎችን በመቀየር ላይ…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ፎቶዎችን እንዲቀይር ይፈቀድለት?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ፎቶዎችን እንዲቀይር ይፈቀድለት?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ፎቶዎችን በመቀየር ላይ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ፎቶዎችን በመቀየር ላይ…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ንጥሎችን እንዲቀይር ይፈቀድለት?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ንጥሎችን እንዲቀይር ይፈቀድለት?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ንጥሎችን በመቀየር ላይ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ንጥሎችን በመቀየር ላይ…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ኦዲዮ ፋይሎችን ወደ መጣያ እንዲወስድ ይፈቀድለት?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ኦዲዮ ፋይሎችን ወደ መጣያ እንዲወስድ ይፈቀድለት?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> የድምጽ ፋይሎችን ወደ መጣያ በመውሰድ ላይ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> የድምጽ ፋይሎችን ወደ መጣያ በመውሰድ ላይ…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ቪዲዮዎችን ወደ መጣያ እንዲወስድ ይፈቀድለት?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ቪዲዮዎችን ወደ መጣያ እንዲወስድ ይፈቀድለት?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ቪዱዮዎችን ወደ መጣያ በመውሰድ ላይ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ቪዱዮዎችን ወደ መጣያ በመውሰድ ላይ…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ፎቶዎችን ወደ መጣያ እንዲወስድ ይፈቀድለት?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ፎቶዎችን ወደ መጣያ እንዲወስድ ይፈቀድለት?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ፎቶዎችን ወደ መጣያ በመውሰድ ላይ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ፎቶዎችን ወደ መጣያ በመውሰድ ላይ…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ንጥሎችን ወደ መጣያ እንዲወስድ ይፈቀድለት?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ንጥሎችን ወደ መጣያ እንዲወስድ ይፈቀድለት?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ንጥሎችን ወደ መጣያ በመውሰድ ላይ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ንጥሎችን ወደ መጣያ በመውሰድ ላይ…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ኦዲዮ ፋይሎችን ከመጣያ እንዲያስወጣ ይፈቀድለት?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ኦዲዮ ፋይሎችን ከመጣያ እንዲያስወጣ ይፈቀድለት?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> የኦዲዮ ፋይሎችን ከመጣያ በማስወጣት ላይ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> የኦዲዮ ፋይሎችን ከመጣያ በማስወጣት ላይ…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ቪዲዮዎችን ከመጣያ እንዲያስወጣ ይፈቀድለት?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ቪዲዮዎችን ከመጣያ እንዲያስወጣ ይፈቀድለት?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ቪዲዮዎችን ከመጣያ በማስወጣት ላይ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ቪዲዮዎችን ከመጣያ በማስወጣት ላይ…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ፎቶዎችን ከመጣያ እንዲያስወጣ ይፈቀድለት?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ፎቶዎችን ከመጣያ እንዲያስወጣ ይፈቀድለት?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ፎቶዎችን ከመጣያ በማስወጣት ላይ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ፎቶዎችን ከመጣያ በማስወጣት ላይ…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ንጥሎችን ከመጣያ እንዲያስወጣ ይፈቀድለት?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ንጥሎችን ከመጣያ እንዲያስወጣ ይፈቀድለት?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ንጥሎችን ከመጣያ በማስወጣት ላይ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ንጥሎችን ከመጣያ በማስወጣት ላይ…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> የኦዲዮ ፋይሎችን እንዲሰረዝ ይፈቀድለት?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> የኦዲዮ ፋይሎችን እንዲሰረዝ ይፈቀድለት?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> የኦዲዮ ፋይሎችን በመሰረዝ ላይ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> የኦዲዮ ፋይሎችን በመሰረዝ ላይ…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ቪዲዮዎችን እንዲሰረዝ ይፈቀድለት?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ቪዲዮዎችን እንዲሰረዝ ይፈቀድለት?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ቪዲዮዎችን በመሰረዝ ላይ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ቪዲዮዎችን በመሰረዝ ላይ…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ፎቶዎችን እንዲሰረዝ ይፈቀድለት?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ፎቶዎችን እንዲሰረዝ ይፈቀድለት?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ፎቶዎችን በመሰረዝ ላይ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ፎቶዎችን በመሰረዝ ላይ…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ንጥሎችን እንዲሰረዝ ይፈቀድለት?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> ንጥሎችን እንዲሰረዝ ይፈቀድለት?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ንጥሎችን በመሰረዝ ላይ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ንጥሎችን በመሰረዝ ላይ…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> የሚዲያ ፋይሎችን ማሄድ አይችልም"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"ሚዲያን ማሰናዳት ተሰርዟል"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"ሚዲያን የማሰናዳት ስህተት"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"ሚዲያን የማሰናዳት ስኬት"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"ሚዲያን ማሰናዳት ተጀምሯል"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"ሚዲያን በማሰናዳት ላይ…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"ይቅር"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"ጠብቅ"</string>
</resources>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index c5d7cea..9fef177 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -59,6 +59,14 @@
<item quantity="other">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بتعديل <xliff:g id="COUNT">^2</xliff:g> ملف صوتي؟</item>
<item quantity="one">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_0">^1</xliff:g> بتعديل هذا الملف الصوتي؟</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="zero">جارٍ تعديل <xliff:g id="COUNT">^1</xliff:g> ملف صوتي…</item>
+ <item quantity="two">جارٍ تعديل ملفَين صوتين (<xliff:g id="COUNT">^1</xliff:g>)…</item>
+ <item quantity="few">جارٍ تعديل <xliff:g id="COUNT">^1</xliff:g> ملفات صوتية…</item>
+ <item quantity="many">جارٍ تعديل <xliff:g id="COUNT">^1</xliff:g> ملفًا صوتيًا…</item>
+ <item quantity="other">جارٍ تعديل <xliff:g id="COUNT">^1</xliff:g> ملف صوتي…</item>
+ <item quantity="one">جارٍ تعديل ملف صوتي واحد…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="zero">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بتعديل <xliff:g id="COUNT">^2</xliff:g> فيديو؟</item>
<item quantity="two">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بتعديل فيديوهين (<xliff:g id="COUNT">^2</xliff:g>)؟</item>
@@ -67,6 +75,14 @@
<item quantity="other">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بتعديل <xliff:g id="COUNT">^2</xliff:g> فيديو؟</item>
<item quantity="one">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_0">^1</xliff:g> بتعديل هذا الفيديو؟</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="zero">جارٍ تعديل <xliff:g id="COUNT">^1</xliff:g> فيديو…</item>
+ <item quantity="two">جارٍ تعديل فيديوهين (<xliff:g id="COUNT">^1</xliff:g>)…</item>
+ <item quantity="few">جارٍ تعديل <xliff:g id="COUNT">^1</xliff:g> فيديوهات…</item>
+ <item quantity="many">جارٍ تعديل <xliff:g id="COUNT">^1</xliff:g> فيديو…</item>
+ <item quantity="other">جارٍ تعديل <xliff:g id="COUNT">^1</xliff:g> فيديو…</item>
+ <item quantity="one">جارٍ تعديل فيديو واحد…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="zero">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بتعديل <xliff:g id="COUNT">^2</xliff:g> صورة؟</item>
<item quantity="two">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بتعديل صورتين (<xliff:g id="COUNT">^2</xliff:g>)؟</item>
@@ -75,6 +91,14 @@
<item quantity="other">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بتعديل <xliff:g id="COUNT">^2</xliff:g> صورة؟</item>
<item quantity="one">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_0">^1</xliff:g> بتعديل هذه الصورة؟</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="zero">جارٍ تعديل <xliff:g id="COUNT">^1</xliff:g> صورة…</item>
+ <item quantity="two">جارٍ تعديل صورتين (<xliff:g id="COUNT">^1</xliff:g>)…</item>
+ <item quantity="few">جارٍ تعديل <xliff:g id="COUNT">^1</xliff:g> صور…</item>
+ <item quantity="many">جارٍ تعديل <xliff:g id="COUNT">^1</xliff:g> صورة…</item>
+ <item quantity="other">جارٍ تعديل <xliff:g id="COUNT">^1</xliff:g> صورة…</item>
+ <item quantity="one">جارٍ تعديل صورة واحدة…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="zero">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بتعديل <xliff:g id="COUNT">^2</xliff:g> عنصر؟</item>
<item quantity="two">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بتعديل عنصرين (<xliff:g id="COUNT">^2</xliff:g>)؟</item>
@@ -83,6 +107,14 @@
<item quantity="other">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بتعديل <xliff:g id="COUNT">^2</xliff:g> عنصر؟</item>
<item quantity="one">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_0">^1</xliff:g> بتعديل هذا العنصر؟</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="zero">جارٍ تعديل <xliff:g id="COUNT">^1</xliff:g> عنصر…</item>
+ <item quantity="two">جارٍ تعديل عنصرين (<xliff:g id="COUNT">^1</xliff:g>)…</item>
+ <item quantity="few">جارٍ تعديل <xliff:g id="COUNT">^1</xliff:g> عناصر…</item>
+ <item quantity="many">جارٍ تعديل <xliff:g id="COUNT">^1</xliff:g> عنصرًا…</item>
+ <item quantity="other">جارٍ تعديل <xliff:g id="COUNT">^1</xliff:g> عنصر…</item>
+ <item quantity="one">جارٍ تعديل عنصر واحد…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="zero">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بنقل <xliff:g id="COUNT">^2</xliff:g> ملف صوتي إلى المهملات؟</item>
<item quantity="two">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بنقل ملفين صوتيين (<xliff:g id="COUNT">^2</xliff:g>) إلى المهملات؟</item>
@@ -91,6 +123,14 @@
<item quantity="other">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بنقل <xliff:g id="COUNT">^2</xliff:g> ملف صوتي إلى المهملات؟</item>
<item quantity="one">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_0">^1</xliff:g> بنقل هذا الملف الصوتي إلى المهملات؟</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="zero">جارٍ نقل <xliff:g id="COUNT">^1</xliff:g> ملف صوتي إلى المهملات…</item>
+ <item quantity="two">جارٍ نقل ملفَين صوتين (<xliff:g id="COUNT">^1</xliff:g>) إلى المهملات…</item>
+ <item quantity="few">جارٍ نقل <xliff:g id="COUNT">^1</xliff:g> ملفات صوتية إلى المهملات…</item>
+ <item quantity="many">جارٍ نقل <xliff:g id="COUNT">^1</xliff:g> ملفًا صوتيًا إلى المهملات…</item>
+ <item quantity="other">جارٍ نقل <xliff:g id="COUNT">^1</xliff:g> ملف صوتي إلى المهملات…</item>
+ <item quantity="one">جارٍ نقل ملف صوتي واحد إلى المهملات…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="zero">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بنقل <xliff:g id="COUNT">^2</xliff:g> فيديو إلى المهملات؟</item>
<item quantity="two">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بنقل فيديوهين (<xliff:g id="COUNT">^2</xliff:g>) إلى المهملات؟</item>
@@ -99,6 +139,14 @@
<item quantity="other">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بنقل <xliff:g id="COUNT">^2</xliff:g> فيديو إلى المهملات؟</item>
<item quantity="one">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_0">^1</xliff:g> بنقل هذا الفيديو إلى المهملات؟</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="zero">جارٍ نقل <xliff:g id="COUNT">^1</xliff:g> فيديو إلى المهملات…</item>
+ <item quantity="two">جارٍ نقل فيديوهين (<xliff:g id="COUNT">^1</xliff:g>) إلى المهملات…</item>
+ <item quantity="few">جارٍ نقل <xliff:g id="COUNT">^1</xliff:g> فيديوهات إلى المهملات…</item>
+ <item quantity="many">جارٍ نقل <xliff:g id="COUNT">^1</xliff:g> فيديو إلى المهملات…</item>
+ <item quantity="other">جارٍ نقل <xliff:g id="COUNT">^1</xliff:g> فيديو إلى المهملات…</item>
+ <item quantity="one">جارٍ نقل فيديو واحد إلى المهملات…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="zero">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بنقل <xliff:g id="COUNT">^2</xliff:g> صورة إلى المهملات؟</item>
<item quantity="two">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بنقل صورتين (<xliff:g id="COUNT">^2</xliff:g>) إلى المهملات؟</item>
@@ -107,6 +155,14 @@
<item quantity="other">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بنقل <xliff:g id="COUNT">^2</xliff:g> صورة إلى المهملات؟</item>
<item quantity="one">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_0">^1</xliff:g> بنقل هذه الصورة إلى المهملات؟</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="zero">جارٍ نقل <xliff:g id="COUNT">^1</xliff:g> صورة إلى المهملات…</item>
+ <item quantity="two">جارٍ نقل صورتين (<xliff:g id="COUNT">^1</xliff:g>) إلى المهملات…</item>
+ <item quantity="few">جارٍ نقل <xliff:g id="COUNT">^1</xliff:g> صور إلى المهملات…</item>
+ <item quantity="many">جارٍ نقل <xliff:g id="COUNT">^1</xliff:g> صورة إلى المهملات…</item>
+ <item quantity="other">جارٍ نقل <xliff:g id="COUNT">^1</xliff:g> صورة إلى المهملات…</item>
+ <item quantity="one">جارٍ نقل صورة واحدة إلى المهملات…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="zero">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بنقل <xliff:g id="COUNT">^2</xliff:g> عنصر إلى المهملات؟</item>
<item quantity="two">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بنقل عنصرين (<xliff:g id="COUNT">^2</xliff:g>) إلى المهملات؟</item>
@@ -115,6 +171,14 @@
<item quantity="other">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بنقل <xliff:g id="COUNT">^2</xliff:g> عنصر إلى المهملات؟</item>
<item quantity="one">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_0">^1</xliff:g> بنقل هذا العنصر إلى المهملات؟</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="zero">جارٍ نقل <xliff:g id="COUNT">^1</xliff:g> عنصر إلى المهملات…</item>
+ <item quantity="two">جارٍ نقل عنصرين (<xliff:g id="COUNT">^1</xliff:g>) إلى المهملات…</item>
+ <item quantity="few">جارٍ نقل <xliff:g id="COUNT">^1</xliff:g> عناصر إلى المهملات…</item>
+ <item quantity="many">جارٍ نقل <xliff:g id="COUNT">^1</xliff:g> عنصرًا إلى المهملات…</item>
+ <item quantity="other">جارٍ نقل <xliff:g id="COUNT">^1</xliff:g> عنصر إلى المهملات…</item>
+ <item quantity="one">جارٍ نقل عنصر واحد إلى المهملات…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="zero">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بنقل <xliff:g id="COUNT">^2</xliff:g> ملف صوتي خارج المهملات؟</item>
<item quantity="two">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بنقل ملفين صوتيين (<xliff:g id="COUNT">^2</xliff:g>) خارج المهملات؟</item>
@@ -123,6 +187,14 @@
<item quantity="other">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بنقل <xliff:g id="COUNT">^2</xliff:g> ملف صوتي خارج المهملات؟</item>
<item quantity="one">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_0">^1</xliff:g> بنقل الملف الصوتي هذا خارج المهملات؟</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="zero">جارٍ إخراج <xliff:g id="COUNT">^1</xliff:g> ملف صوتي من المهملات…</item>
+ <item quantity="two">جارٍ إخراج ملفَين صوتين (<xliff:g id="COUNT">^1</xliff:g>) من المهملات…</item>
+ <item quantity="few">جارٍ إخراج <xliff:g id="COUNT">^1</xliff:g> ملفات صوتية من المهملات…</item>
+ <item quantity="many">جارٍ إخراج <xliff:g id="COUNT">^1</xliff:g> ملفًا صوتيًا من المهملات…</item>
+ <item quantity="other">جارٍ إخراج <xliff:g id="COUNT">^1</xliff:g> ملف صوتي من المهملات…</item>
+ <item quantity="one">جارٍ إخراج ملف صوتي واحد من المهملات…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="zero">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بنقل <xliff:g id="COUNT">^2</xliff:g> فيديو خارج المهملات؟</item>
<item quantity="two">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بنقل فيديوهين (<xliff:g id="COUNT">^2</xliff:g>) خارج المهملات؟</item>
@@ -131,6 +203,14 @@
<item quantity="other">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بنقل <xliff:g id="COUNT">^2</xliff:g> فيديو خارج المهملات؟</item>
<item quantity="one">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_0">^1</xliff:g> بنقل هذا الفيديو خارج المهملات؟</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="zero">جارٍ إخراج <xliff:g id="COUNT">^1</xliff:g> فيديو من المهملات…</item>
+ <item quantity="two">جارٍ إخراج فيديوهين (<xliff:g id="COUNT">^1</xliff:g>) من المهملات…</item>
+ <item quantity="few">جارٍ إخراج <xliff:g id="COUNT">^1</xliff:g> فيديوهات من المهملات…</item>
+ <item quantity="many">جارٍ إخراج <xliff:g id="COUNT">^1</xliff:g> فيديو من المهملات…</item>
+ <item quantity="other">جارٍ إخراج <xliff:g id="COUNT">^1</xliff:g> فيديو من المهملات…</item>
+ <item quantity="one">جارٍ إخراج فيديو واحد من المهملات…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="zero">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بنقل <xliff:g id="COUNT">^2</xliff:g> صورة خارج المهملات؟</item>
<item quantity="two">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بنقل صورتين (<xliff:g id="COUNT">^2</xliff:g>) خارج المهملات؟</item>
@@ -139,6 +219,14 @@
<item quantity="other">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بنقل <xliff:g id="COUNT">^2</xliff:g> صورة خارج المهملات؟</item>
<item quantity="one">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_0">^1</xliff:g> بنقل هذه الصورة خارج المهملات؟</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="zero">جارٍ إخراج <xliff:g id="COUNT">^1</xliff:g> صورة من المهملات…</item>
+ <item quantity="two">جارٍ إخراج صورتين (<xliff:g id="COUNT">^1</xliff:g>) من المهملات…</item>
+ <item quantity="few">جارٍ إخراج <xliff:g id="COUNT">^1</xliff:g> صور من المهملات…</item>
+ <item quantity="many">جارٍ إخراج <xliff:g id="COUNT">^1</xliff:g> صورة من المهملات…</item>
+ <item quantity="other">جارٍ إخراج <xliff:g id="COUNT">^1</xliff:g> صورة من المهملات…</item>
+ <item quantity="one">جارٍ إخراج صورة واحدة من المهملات…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="zero">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بنقل <xliff:g id="COUNT">^2</xliff:g> عنصر خارج المهملات؟</item>
<item quantity="two">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بنقل عنصرين (<xliff:g id="COUNT">^2</xliff:g>) خارج المهملات؟</item>
@@ -147,6 +235,14 @@
<item quantity="other">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بنقل <xliff:g id="COUNT">^2</xliff:g> عنصر خارج المهملات؟</item>
<item quantity="one">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_0">^1</xliff:g> بنقل هذا العنصر خارج المهملات؟</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="zero">جارٍ إخراج <xliff:g id="COUNT">^1</xliff:g> عنصر من المهملات…</item>
+ <item quantity="two">جارٍ إخراج عنصرين (<xliff:g id="COUNT">^1</xliff:g>) من المهملات…</item>
+ <item quantity="few">جارٍ إخراج <xliff:g id="COUNT">^1</xliff:g> عناصر من المهملات…</item>
+ <item quantity="many">جارٍ إخراج <xliff:g id="COUNT">^1</xliff:g> عنصرًا من المهملات…</item>
+ <item quantity="other">جارٍ إخراج <xliff:g id="COUNT">^1</xliff:g> عنصر من المهملات…</item>
+ <item quantity="one">جارٍ إخراج عنصر واحد من المهملات…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="zero">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بحذف <xliff:g id="COUNT">^2</xliff:g> ملف صوتي؟</item>
<item quantity="two">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بحذف ملفين صوتيين (<xliff:g id="COUNT">^2</xliff:g>)؟</item>
@@ -155,6 +251,14 @@
<item quantity="other">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بحذف <xliff:g id="COUNT">^2</xliff:g> ملف صوتي؟</item>
<item quantity="one">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_0">^1</xliff:g> بحذف هذا الملف الصوتي؟</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="zero">جارٍ حذف <xliff:g id="COUNT">^1</xliff:g> ملف صوتي…</item>
+ <item quantity="two">جارٍ حذف ملفَين صوتين (<xliff:g id="COUNT">^1</xliff:g>)…</item>
+ <item quantity="few">جارٍ حذف <xliff:g id="COUNT">^1</xliff:g> ملفات صوتية…</item>
+ <item quantity="many">جارٍ حذف <xliff:g id="COUNT">^1</xliff:g> ملفًا صوتيًا…</item>
+ <item quantity="other">جارٍ حذف <xliff:g id="COUNT">^1</xliff:g> ملف صوتي…</item>
+ <item quantity="one">جارٍ حذف ملف صوتي واحد…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="zero">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بحذف <xliff:g id="COUNT">^2</xliff:g> فيديو؟</item>
<item quantity="two">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بحذف فيديوهين (<xliff:g id="COUNT">^2</xliff:g>)؟</item>
@@ -163,6 +267,14 @@
<item quantity="other">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بحذف <xliff:g id="COUNT">^2</xliff:g> فيديو؟</item>
<item quantity="one">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_0">^1</xliff:g> بحذف هذا الفيديو؟</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="zero">جارٍ حذف <xliff:g id="COUNT">^1</xliff:g> فيديو…</item>
+ <item quantity="two">جارٍ حذف فيديوهين (<xliff:g id="COUNT">^1</xliff:g>)…</item>
+ <item quantity="few">جارٍ حذف <xliff:g id="COUNT">^1</xliff:g> فيديوهات…</item>
+ <item quantity="many">جارٍ حذف <xliff:g id="COUNT">^1</xliff:g> فيديو…</item>
+ <item quantity="other">جارٍ حذف <xliff:g id="COUNT">^1</xliff:g> فيديو…</item>
+ <item quantity="one">جارٍ حذف فيديو واحد…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="zero">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بحذف <xliff:g id="COUNT">^2</xliff:g> صورة؟</item>
<item quantity="two">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بحذف صورتين (<xliff:g id="COUNT">^2</xliff:g>)؟</item>
@@ -171,6 +283,14 @@
<item quantity="other">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بحذف <xliff:g id="COUNT">^2</xliff:g> صورة؟</item>
<item quantity="one">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_0">^1</xliff:g> بحذف صورة واحدة؟</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="zero">جارٍ حذف <xliff:g id="COUNT">^1</xliff:g> صورة…</item>
+ <item quantity="two">جارٍ حذف صورتين (<xliff:g id="COUNT">^1</xliff:g>)…</item>
+ <item quantity="few">جارٍ حذف <xliff:g id="COUNT">^1</xliff:g> صور…</item>
+ <item quantity="many">جارٍ حذف <xliff:g id="COUNT">^1</xliff:g> صورة…</item>
+ <item quantity="other">جارٍ حذف <xliff:g id="COUNT">^1</xliff:g> صورة…</item>
+ <item quantity="one">جارٍ حذف صورة واحدة…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="zero">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بحذف <xliff:g id="COUNT">^2</xliff:g> عنصر؟</item>
<item quantity="two">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بحذف عنصرين (<xliff:g id="COUNT">^2</xliff:g>)؟</item>
@@ -179,4 +299,20 @@
<item quantity="other">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_1">^1</xliff:g> بحذف <xliff:g id="COUNT">^2</xliff:g> عنصر؟</item>
<item quantity="one">هل تريد السماح لتطبيق <xliff:g id="APP_NAME_0">^1</xliff:g> بحذف هذا العنصر؟</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="zero">جارٍ حذف <xliff:g id="COUNT">^1</xliff:g> عنصر…</item>
+ <item quantity="two">جارٍ حذف عنصرين (<xliff:g id="COUNT">^1</xliff:g>)…</item>
+ <item quantity="few">جارٍ حذف <xliff:g id="COUNT">^1</xliff:g> عناصر…</item>
+ <item quantity="many">جارٍ حذف <xliff:g id="COUNT">^1</xliff:g> عنصرًا…</item>
+ <item quantity="other">جارٍ حذف <xliff:g id="COUNT">^1</xliff:g> عنصر…</item>
+ <item quantity="one">جارٍ حذف عنصر واحد…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"يتعذّر على التطبيق <xliff:g id="APP_NAME">%s</xliff:g> معالجة ملفات الوسائط."</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"تم إلغاء معالجة الوسائط."</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"حدث خطأ أثناء معالجة الوسائط."</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"تمت عملية معالجة الوسائط."</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"بدأت عملية معالجة الوسائط."</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"جارٍ معالجة الوسائط…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"إلغاء"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"الانتظار"</string>
</resources>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index 35449a8..fbb3a35 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -47,64 +47,136 @@
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> টা অডিঅ’ ফাইল সংশোধন কৰিবলৈ অনুমতি দিবনে?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> টা অডিঅ’ ফাইল সংশোধন কৰিবলৈ অনুমতি দিবনে?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> টা অডিঅ’ ফাইল সংশোধন কৰি থকা হৈছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> টা অডিঅ’ ফাইল সংশোধন কৰি থকা হৈছে…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> টা ভিডিঅ’ সংশোধন কৰিবলৈ অনুমতি দিবনে?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> টা ভিডিঅ’ সংশোধন কৰিবলৈ অনুমতি দিবনে?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> টা ভিডিঅ’ সংশোধন কৰি থকা হৈছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> টা ভিডিঅ’ সংশোধন কৰি থকা হৈছে…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> খন ফট’ সংশোধন কৰিবলৈ অনুমতি দিবনে?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> খন ফট’ সংশোধন কৰিবলৈ অনুমতি দিবনে?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> খন ফট’ সংশোধন কৰি থকা হৈছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> খন ফট’ সংশোধন কৰি থকা হৈছে…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> টা বস্তু সংশোধন কৰিবলৈ অনুমতি দিবনে?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> টা বস্তু সংশোধন কৰিবলৈ অনুমতি দিবনে?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> টা বস্তু সংশোধন কৰি থকা হৈছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> টা বস্তু সংশোধন কৰি থকা হৈছে…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> টা অডিঅ’ ফাইল ট্ৰেশ্বলৈ স্থানান্তৰ কৰিবলৈ অনুমতি দিবনে?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> টা অডিঅ’ ফাইল ট্ৰেশ্বলৈ স্থানান্তৰ কৰিবলৈ অনুমতি দিবনে?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> টা অডিঅ’ ফাইল ট্ৰেশ্বলৈ নি থকা হৈছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> টা অডিঅ’ ফাইল ট্ৰেশ্বলৈ নি থকা হৈছে…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> টা ভিডিঅ’ ট্ৰেশ্বলৈ স্থানান্তৰ কৰিবলৈ অনুমতি দিবনে?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> টা ভিডিঅ’ ট্ৰেশ্বলৈ স্থানান্তৰ কৰিবলৈ অনুমতি দিবনে?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> টা ভিডিঅ’ ট্ৰেশ্বলৈ নি থকা হৈছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> টা ভিডিঅ’ ট্ৰেশ্বলৈ নি থকা হৈছে…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> খন ফট’ ট্ৰেশ্বলৈ স্থানান্তৰ কৰিবলৈ অনুমতি দিবনে?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> খন ফট’ ট্ৰেশ্বলৈ স্থানান্তৰ কৰিবলৈ অনুমতি দিবনে?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> খন ফট’ ট্ৰেশ্বলৈ নি থকা হৈছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> খন ফট’ ট্ৰেশ্বলৈ নি থকা হৈছে…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> টা বস্তু ট্ৰেশ্বলৈ স্থানান্তৰ কৰিবলৈ অনুমতি দিবনে?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> টা বস্তু ট্ৰেশ্বলৈ স্থানান্তৰ কৰিবলৈ অনুমতি দিবনে?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> টা বস্তু ট্ৰেশ্বলৈ নি থকা হৈছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> টা বস্তু ট্ৰেশ্বলৈ নি থকা হৈছে…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> টা অডিঅ’ ফাইল ট্ৰেশ্বৰ পৰা বাহিৰলৈ স্থানান্তৰ কৰিবলৈ অনুমতি দিবনে?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> টা অডিঅ’ ফাইল ট্ৰেশ্বৰ পৰা বাহিৰলৈ স্থানান্তৰ কৰিবলৈ অনুমতি দিবনে?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> টা অডিঅ’ ফাইল ট্ৰেশ্বৰ পৰা বাহিৰলৈ নি থকা হৈছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> টা অডিঅ’ ফাইল ট্ৰেশ্বৰ পৰা বাহিৰলৈ নি থকা হৈছে…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> টা ভিডিঅ’ ট্ৰেশ্বৰ পৰা বাহিৰলৈ স্থানান্তৰ কৰিবলৈ অনুমতি দিবনে?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> টা ভিডিঅ’ ট্ৰেশ্বৰ পৰা বাহিৰলৈ স্থানান্তৰ কৰিবলৈ অনুমতি দিবনে?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> টা ভিডিঅ’ ট্ৰেশ্বৰ পৰা বাহিৰলৈ নি থকা হৈছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> টা ভিডিঅ’ ট্ৰেশ্বৰ পৰা বাহিৰলৈ নি থকা হৈছে…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> খন ফট’ ট্ৰেশ্বৰ পৰা বাহিৰলৈ স্থানান্তৰ কৰিবলৈ অনুমতি দিবনে?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> খন ফট’ ট্ৰেশ্বৰ পৰা বাহিৰলৈ স্থানান্তৰ কৰিবলৈ অনুমতি দিবনে?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> খন ফট’ ট্ৰেশ্বৰ পৰা বাহিৰলৈ নি থকা হৈছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> খন ফট’ ট্ৰেশ্বৰ পৰা বাহিৰলৈ নি থকা হৈছে…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> টা বস্তু ট্ৰেশ্বৰ পৰা বাহিৰলৈ স্থানান্তৰ কৰিবলৈ অনুমতি দিবনে?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> টা বস্তু ট্ৰেশ্বৰ পৰা বাহিৰলৈ স্থানান্তৰ কৰিবলৈ অনুমতি দিবনে?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> টা বস্তু ট্ৰেশ্বৰ পৰা বাহিৰলৈ নি থকা হৈছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> টা বস্তু ট্ৰেশ্বৰ পৰা বাহিৰলৈ নি থকা হৈছে…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> টা অডিঅ’ ফাইল মচিবলৈ অনুমতি দিবনে?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> টা অডিঅ’ ফাইল মচিবলৈ অনুমতি দিবনে?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> টা অডিঅ’ ফাইল মচি থকা হৈছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> টা অডিঅ’ ফাইল মচি থকা হৈছে…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> টা ভিডিঅ’ মচিবলৈ অনুমতি দিবনে?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> টা ভিডিঅ’ মচিবলৈ অনুমতি দিবনে?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> টা ভিডিঅ’ মচি থকা হৈছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> টা ভিডিঅ’ মচি থকা হৈছে…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> খন ফট’ মচিবলৈ অনুমতি দিবনে?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> খন ফট’ মচিবলৈ অনুমতি দিবনে?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> খন ফট’ মচি থকা হৈছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> খন ফট’ মচি থকা হৈছে…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> টা বস্তু মচিবলৈ অনুমতি দিবনে?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ক <xliff:g id="COUNT">^2</xliff:g> টা বস্তু মচিবলৈ অনুমতি দিবনে?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> টা বস্তু মচি থকা হৈছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> টা বস্তু মচি থকা হৈছে…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g>এ মিডিয়া ফাইলৰ প্ৰক্ৰিয়াকৰণ কৰিব নোৱাৰে"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"মিডিয়াৰ প্ৰক্ৰিয়াকৰণ বাতিল কৰা হৈছে"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"মিডিয়াৰ প্ৰক্ৰিয়াকৰণত আসোঁৱাহ হৈছে"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"মিডিয়াৰ প্ৰক্ৰিয়াকৰণ সফল হৈছে"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"মিডিয়াৰ প্ৰক্ৰিয়াকৰণ আৰম্ভ হৈছে"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"মিডিয়াৰ প্ৰক্ৰিয়াকৰণ কৰি থকা হৈছে…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"বাতিল কৰক"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"অপেক্ষা কৰক"</string>
</resources>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index a8d2ab3..785ada1 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> tətbiqinə <xliff:g id="COUNT">^2</xliff:g> audio fayla dəyişiklik etmək icazəsi verilsin?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> tətbiqinə bu audio fayla dəyişiklik etmək icazəsi verilsin?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> audio fayl dəyişdirilir…</item>
+ <item quantity="one">Audio fayl dəyişdirilir…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> tətbiqinə <xliff:g id="COUNT">^2</xliff:g> videoya dəyişiklik etmək icazəsi verilsin?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> tətbiqinə bu videoya dəyişiklik etmək icazəsi verilsin?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> video dəyişdirilir…</item>
+ <item quantity="one">Video dəyişdirilir…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> tətbiqinə <xliff:g id="COUNT">^2</xliff:g> fotoya dəyişiklik etmək icazəsi verilsin?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> tətbiqinə bu fotoya dəyişiklik etmək icazəsi verilsin?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> foto dəyişdirilir…</item>
+ <item quantity="one">Foto dəyişdirilir…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> tətbiqinə <xliff:g id="COUNT">^2</xliff:g> elementə dəyişiklik etmək icazəsi verilsin?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> tətbiqinə bu elementə dəyişiklik etmək icazəsi verilsin?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> element dəyişdirilir…</item>
+ <item quantity="one">Element dəyişdirilir…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> tətbiqinə <xliff:g id="COUNT">^2</xliff:g> audio faylı zibil qutusuna köçürmək icazəsi verilsin?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> tətbiqinə bu audio faylı zibil qutusuna köçürmək icazəsi verilsin?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> audio fayl zibil qutusuna köçürülür…</item>
+ <item quantity="one">Audio fayl zibil qutusuna köçürülür…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> tətbiqinə <xliff:g id="COUNT">^2</xliff:g> videonu zibil qutusuna köçürmək icazəsi verilsin?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> tətbiqinə bu videonu zibil qutusuna köçürmək icazəsi verilsin?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> video zibil qutusuna köçürülür…</item>
+ <item quantity="one">Video zibil qutusuna köçürülür…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> tətbiqinə <xliff:g id="COUNT">^2</xliff:g> fotonu zibil qutusuna köçürmək icazəsi verilsin?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> tətbiqinə bu fotonu zibil qutusuna köçürmək icazəsi verilsin?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> foto zibil qutusuna köçürülür…</item>
+ <item quantity="one">Foto zibil qutusuna köçürülür…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> tətbiqinə <xliff:g id="COUNT">^2</xliff:g> elementi zibil qutusuna köçürmək icazəsi verilsin?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> tətbiqinə bu elementi zibil qutusuna köçürmək icazəsi verilsin?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> element zibil qutusuna köçürülür…</item>
+ <item quantity="one">Element zibil qutusuna köçürülür…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> tətbiqinə <xliff:g id="COUNT">^2</xliff:g> audio faylı zibil qutusundan çıxarmaq icazəsi verilsin?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> tətbiqinə bu audio faylı zibil qutusundan çıxarmaq icazəsi verilsin?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> audio fayl zibil qutusundan çıxarılır…</item>
+ <item quantity="one">Audio fayl zibil qutusundan çıxarılır…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> tətbiqinə <xliff:g id="COUNT">^2</xliff:g> videonu zibil qutusundan çıxarmaq icazəsi verilsin?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> tətbiqinə bu videonu zibil qutusundan çıxarmaq icazəsi verilsin?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> video zibil qutusundan çıxarılır…</item>
+ <item quantity="one">Video zibil qutusundan çıxarılır…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> tətbiqinə <xliff:g id="COUNT">^2</xliff:g> fotonu zibil qutusundan çıxarmaq icazəsi verilsin?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> tətbiqinə bu fotonu zibil qutusundan çıxarmaq icazəsi verilsin?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> foto zibil qutusundan çıxarılır…</item>
+ <item quantity="one">Foto zibil qutusundan çıxarılır…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> tətbiqinə <xliff:g id="COUNT">^2</xliff:g> elementi zibil qutusundan çıxarmaq icazəsi verilsin?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> tətbiqinə bu elementi zibil qutusundan çıxarmaq icazəsi verilsin?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> element zibil qutusundan çıxarılır…</item>
+ <item quantity="one">Element zibil qutusundan çıxarılır…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> tətbiqinə <xliff:g id="COUNT">^2</xliff:g> audio faylı silmək icazəsi verilsin?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> tətbiqinə bu audio faylı silmək icazəsi verilsin?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> audio fayl silinir…</item>
+ <item quantity="one">Audio fayl silinir…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> tətbiqinə <xliff:g id="COUNT">^2</xliff:g> videonu silmək icazəsi verilsin?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> tətbiqinə bu videonu silmək icazəsi verilsin?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> video silinir…</item>
+ <item quantity="one">Video silinir…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> tətbiqinə <xliff:g id="COUNT">^2</xliff:g> fotonu silmək icazəsi verilsin?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> tətbiqinə bu fotonu silmək icazəsi verilsin?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> foto silinir…</item>
+ <item quantity="one">Foto silinir…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> tətbiqinə <xliff:g id="COUNT">^2</xliff:g> elementi silmək icazəsi verilsin?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> tətbiqinə bu elementi silmək icazəsi verilsin?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> element silinir…</item>
+ <item quantity="one">Element silinir…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> media fayllarını emal edə bilmir"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Media emalı ləğv edilib"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Media emalı zamanı xəta oldu"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Media emalı uğurlu oldu"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Media emalı başladılıb"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Media emal edilir…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Ləğv edin"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Gözləyin"</string>
</resources>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 9756151..a4a20c8 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -50,79 +50,167 @@
<item quantity="few">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> izmeni <xliff:g id="COUNT">^2</xliff:g> audio datoteke?</item>
<item quantity="other">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> izmeni <xliff:g id="COUNT">^2</xliff:g> audio datoteka?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="one">Menja se <xliff:g id="COUNT">^1</xliff:g> audio fajl…</item>
+ <item quantity="few">Menjaju se <xliff:g id="COUNT">^1</xliff:g> audio fajla…</item>
+ <item quantity="other">Menja se <xliff:g id="COUNT">^1</xliff:g> audio fajlova…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="one">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> izmeni <xliff:g id="COUNT">^2</xliff:g> video?</item>
<item quantity="few">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> izmeni <xliff:g id="COUNT">^2</xliff:g> video snimka?</item>
<item quantity="other">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> izmeni <xliff:g id="COUNT">^2</xliff:g> video snimaka?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="one">Menja se <xliff:g id="COUNT">^1</xliff:g> video…</item>
+ <item quantity="few">Menjaju se <xliff:g id="COUNT">^1</xliff:g> video snimka…</item>
+ <item quantity="other">Menja se <xliff:g id="COUNT">^1</xliff:g> video snimaka…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="one">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> izmeni <xliff:g id="COUNT">^2</xliff:g> sliku?</item>
<item quantity="few">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> izmeni <xliff:g id="COUNT">^2</xliff:g> slike?</item>
<item quantity="other">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> izmeni <xliff:g id="COUNT">^2</xliff:g> slika?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="one">Menja se <xliff:g id="COUNT">^1</xliff:g> slika…</item>
+ <item quantity="few">Menjaju se <xliff:g id="COUNT">^1</xliff:g> slike…</item>
+ <item quantity="other">Menja se <xliff:g id="COUNT">^1</xliff:g> slika…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="one">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> izmeni <xliff:g id="COUNT">^2</xliff:g> stavku?</item>
<item quantity="few">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> izmeni <xliff:g id="COUNT">^2</xliff:g> stavke?</item>
<item quantity="other">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> izmeni <xliff:g id="COUNT">^2</xliff:g> stavki?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="one">Menja se <xliff:g id="COUNT">^1</xliff:g> stavka…</item>
+ <item quantity="few">Menjaju se <xliff:g id="COUNT">^1</xliff:g> stavke…</item>
+ <item quantity="other">Menja se <xliff:g id="COUNT">^1</xliff:g> stavki…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="one">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> premesti <xliff:g id="COUNT">^2</xliff:g> audio datoteku u otpad?</item>
<item quantity="few">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> premesti <xliff:g id="COUNT">^2</xliff:g> audio datoteke u otpad?</item>
<item quantity="other">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> premesti <xliff:g id="COUNT">^2</xliff:g> audio datoteka u otpad?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> audio fajl se premešta u otpad…</item>
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> audio fajla se premeštaju u otpad…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> audio fajlova se premešta u otpad…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="one">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> premesti <xliff:g id="COUNT">^2</xliff:g> video u otpad?</item>
<item quantity="few">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> premesti <xliff:g id="COUNT">^2</xliff:g> video snimka u otpad?</item>
<item quantity="other">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> premesti <xliff:g id="COUNT">^2</xliff:g> video snimaka u otpad?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> video se premešta u otpad…</item>
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> video snimka se premeštaju u otpad…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> video snimaka se premešta u otpad…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="one">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> premesti <xliff:g id="COUNT">^2</xliff:g> sliku u otpad?</item>
<item quantity="few">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> premesti <xliff:g id="COUNT">^2</xliff:g> slike u otpad?</item>
<item quantity="other">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> premesti <xliff:g id="COUNT">^2</xliff:g> slika u otpad?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> slika se premešta u otpad…</item>
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> slike se premeštaju u otpad…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> slika se premešta u otpad…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="one">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> premesti <xliff:g id="COUNT">^2</xliff:g> stavku u otpad?</item>
<item quantity="few">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> premesti <xliff:g id="COUNT">^2</xliff:g> stavke u otpad?</item>
<item quantity="other">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> premesti <xliff:g id="COUNT">^2</xliff:g> stavki u otpad?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> stavka se premešta u otpad…</item>
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> stavke se premeštaju u otpad…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> stavki se premešta u otpad…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="one">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> premesti <xliff:g id="COUNT">^2</xliff:g> audio datoteku iz otpada?</item>
<item quantity="few">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> premesti <xliff:g id="COUNT">^2</xliff:g> audio datoteke iz otpada?</item>
<item quantity="other">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> premesti <xliff:g id="COUNT">^2</xliff:g> audio datoteka iz otpada?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> audio fajl se premešta iz otpada…</item>
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> audio fajla se premeštaju iz otpada…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> audio fajlova se premešta iz otpada…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="one">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> premesti <xliff:g id="COUNT">^2</xliff:g> video iz otpada?</item>
<item quantity="few">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> premesti <xliff:g id="COUNT">^2</xliff:g> video snimka iz otpada?</item>
<item quantity="other">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> premesti <xliff:g id="COUNT">^2</xliff:g> video snimaka iz otpada?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> video se premešta iz otpada…</item>
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> video snimka se premeštaju iz otpada…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> video snimaka se premešta iz otpada…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="one">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> premesti <xliff:g id="COUNT">^2</xliff:g> sliku iz otpada?</item>
<item quantity="few">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> premesti <xliff:g id="COUNT">^2</xliff:g> slike iz otpada?</item>
<item quantity="other">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> premesti <xliff:g id="COUNT">^2</xliff:g> slika iz otpada?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> slika se premešta iz otpada…</item>
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> slike se premeštaju iz otpada…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> slika se premešta iz otpada…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="one">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> premesti <xliff:g id="COUNT">^2</xliff:g> stavku iz otpada?</item>
<item quantity="few">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> premesti <xliff:g id="COUNT">^2</xliff:g> stavke iz otpada?</item>
<item quantity="other">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> premesti <xliff:g id="COUNT">^2</xliff:g> stavki iz otpada?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> stavka se premešta iz otpada…</item>
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> stavke se premeštaju iz otpada…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> stavki se premešta iz otpada…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="one">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> izbriše <xliff:g id="COUNT">^2</xliff:g> audio datoteku?</item>
<item quantity="few">Želite li da dozvolite <xliff:g id="APP_NAME_1">^1</xliff:g> izbriše <xliff:g id="COUNT">^2</xliff:g> audio datoteke?</item>
<item quantity="other">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> izbriše <xliff:g id="COUNT">^2</xliff:g> audio datoteka?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="one">Briše se <xliff:g id="COUNT">^1</xliff:g> audio fajl…</item>
+ <item quantity="few">Brišu se <xliff:g id="COUNT">^1</xliff:g> audio fajla…</item>
+ <item quantity="other">Briše se <xliff:g id="COUNT">^1</xliff:g> audio fajlova…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="one">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> izbriše <xliff:g id="COUNT">^2</xliff:g> video?</item>
<item quantity="few">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> izbriše <xliff:g id="COUNT">^2</xliff:g> video snimka?</item>
<item quantity="other">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> izbriše <xliff:g id="COUNT">^2</xliff:g> video snimaka?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="one">Briše se <xliff:g id="COUNT">^1</xliff:g> video…</item>
+ <item quantity="few">Brišu se <xliff:g id="COUNT">^1</xliff:g> video snimka…</item>
+ <item quantity="other">Briše se <xliff:g id="COUNT">^1</xliff:g> video snimaka…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="one">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> izbriše <xliff:g id="COUNT">^2</xliff:g> sliku?</item>
<item quantity="few">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> izbriše <xliff:g id="COUNT">^2</xliff:g> slike?</item>
<item quantity="other">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> izbriše <xliff:g id="COUNT">^2</xliff:g> slika?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="one">Briše se <xliff:g id="COUNT">^1</xliff:g> slika…</item>
+ <item quantity="few">Brišu se <xliff:g id="COUNT">^1</xliff:g> slike…</item>
+ <item quantity="other">Briše se <xliff:g id="COUNT">^1</xliff:g> slika…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="one">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> izbriše <xliff:g id="COUNT">^2</xliff:g> stavku?</item>
<item quantity="few">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> izbriše <xliff:g id="COUNT">^2</xliff:g> stavke?</item>
<item quantity="other">Želite li da dozvolite da <xliff:g id="APP_NAME_1">^1</xliff:g> izbriše <xliff:g id="COUNT">^2</xliff:g> stavki?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="one">Briše se <xliff:g id="COUNT">^1</xliff:g> stavka…</item>
+ <item quantity="few">Brišu se <xliff:g id="COUNT">^1</xliff:g> stavke…</item>
+ <item quantity="other">Briše se <xliff:g id="COUNT">^1</xliff:g> stavki…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> ne može da obradi medijske fajlove"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Obrada medija je otkazana"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Greška pri obradi medija"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Obrada medija je uspela"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Obrada medija je započela"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Obrađuju se mediji…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Otkaži"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Sačekaj"</string>
</resources>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 58bffee..18c1dcc 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -53,94 +53,198 @@
<item quantity="many">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" змяніць <xliff:g id="COUNT">^2</xliff:g> аўдыяфайлаў?</item>
<item quantity="other">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" змяніць <xliff:g id="COUNT">^2</xliff:g> аўдыяфайла?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="one">Змяняецца <xliff:g id="COUNT">^1</xliff:g> аўдыяфайл…</item>
+ <item quantity="few">Змяняюцца <xliff:g id="COUNT">^1</xliff:g> аўдыяфайлы…</item>
+ <item quantity="many">Змяняюцца <xliff:g id="COUNT">^1</xliff:g> аўдыяфайлаў…</item>
+ <item quantity="other">Змяняюцца <xliff:g id="COUNT">^1</xliff:g> аўдыяфайла…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="one">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" змяніць <xliff:g id="COUNT">^2</xliff:g> відэа?</item>
<item quantity="few">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" змяніць <xliff:g id="COUNT">^2</xliff:g> відэа?</item>
<item quantity="many">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" змяніць <xliff:g id="COUNT">^2</xliff:g> відэа?</item>
<item quantity="other">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" змяніць <xliff:g id="COUNT">^2</xliff:g> відэа?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="one">Змяняецца <xliff:g id="COUNT">^1</xliff:g> відэа…</item>
+ <item quantity="few">Змяняюцца <xliff:g id="COUNT">^1</xliff:g> відэа…</item>
+ <item quantity="many">Змяняюцца <xliff:g id="COUNT">^1</xliff:g> відэа…</item>
+ <item quantity="other">Змяняюцца <xliff:g id="COUNT">^1</xliff:g> відэа…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="one">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" змяніць <xliff:g id="COUNT">^2</xliff:g> фота?</item>
<item quantity="few">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" змяніць <xliff:g id="COUNT">^2</xliff:g> фота?</item>
<item quantity="many">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" змяніць <xliff:g id="COUNT">^2</xliff:g> фота?</item>
<item quantity="other">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" змяніць <xliff:g id="COUNT">^2</xliff:g> фота?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="one">Змяняецца <xliff:g id="COUNT">^1</xliff:g> фота…</item>
+ <item quantity="few">Змяняюцца <xliff:g id="COUNT">^1</xliff:g> фота…</item>
+ <item quantity="many">Змяняюцца <xliff:g id="COUNT">^1</xliff:g> фота…</item>
+ <item quantity="other">Змяняюцца <xliff:g id="COUNT">^1</xliff:g> фота…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="one">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" змяніць <xliff:g id="COUNT">^2</xliff:g> элемент?</item>
<item quantity="few">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" змяніць <xliff:g id="COUNT">^2</xliff:g> элементы?</item>
<item quantity="many">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" змяніць <xliff:g id="COUNT">^2</xliff:g> элементаў?</item>
<item quantity="other">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" змяніць <xliff:g id="COUNT">^2</xliff:g> элемента?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="one">Змяняецца <xliff:g id="COUNT">^1</xliff:g> элемент…</item>
+ <item quantity="few">Змяняюцца <xliff:g id="COUNT">^1</xliff:g> элементы…</item>
+ <item quantity="many">Змяняюцца <xliff:g id="COUNT">^1</xliff:g> элементаў…</item>
+ <item quantity="other">Змяняюцца <xliff:g id="COUNT">^1</xliff:g> элемента…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="one">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> аўдыяфайл у сметніцу?</item>
<item quantity="few">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> аўдыяфайлы ў сметніцу?</item>
<item quantity="many">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> аўдыяфайлаў у сметніцу?</item>
<item quantity="other">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> аўдыяфайла ў сметніцу?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> аўдыяфайл перамяшчаецца ў сметніцу…</item>
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> аўдыяфайлы перамяшчаюцца ў сметніцу…</item>
+ <item quantity="many"><xliff:g id="COUNT">^1</xliff:g> аўдыяфайлаў перамяшчаюцца ў сметніцу…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> аўдыяфайла перамяшчаюцца ў сметніцу…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="one">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> відэа ў сметніцу?</item>
<item quantity="few">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> відэа ў сметніцу?</item>
<item quantity="many">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> відэа ў сметніцу?</item>
<item quantity="other">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> відэа ў сметніцу?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> відэа перамяшчаецца ў сметніцу…</item>
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> відэа перамяшчаюцца ў сметніцу…</item>
+ <item quantity="many"><xliff:g id="COUNT">^1</xliff:g> відэа перамяшчаюцца ў сметніцу…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> відэа перамяшчаюцца ў сметніцу…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="one">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> фота ў сметніцу?</item>
<item quantity="few">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> фота ў сметніцу?</item>
<item quantity="many">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> фота ў сметніцу?</item>
<item quantity="other">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> фота ў сметніцу?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> фота перамяшчаецца ў сметніцу…</item>
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> фота перамяшчаюцца ў сметніцу…</item>
+ <item quantity="many"><xliff:g id="COUNT">^1</xliff:g> фота перамяшчаюцца ў сметніцу…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> фота перамяшчаюцца ў сметніцу…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="one">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> элемент у сметніцу?</item>
<item quantity="few">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> элементы ў сметніцу?</item>
<item quantity="many">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> элементаў у сметніцу?</item>
<item quantity="other">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> элемента ў сметніцу?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> элемент перамяшчаецца ў сметніцу…</item>
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> элементы перамяшчаюцца ў сметніцу…</item>
+ <item quantity="many"><xliff:g id="COUNT">^1</xliff:g> элементаў перамяшчаюцца ў сметніцу…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> элемента перамяшчаюцца ў сметніцу…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="one">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> аўдыяфайл са сметніцы?</item>
<item quantity="few">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> аўдыяфайлы са сметніцы?</item>
<item quantity="many">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> аўдыяфайлаў са сметніцы?</item>
<item quantity="other">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> аўдыяфайла са сметніцы?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> аўдыяфайл перамяшчаецца са сметніцы…</item>
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> аўдыяфайлы перамяшчаюцца са сметніцы…</item>
+ <item quantity="many"><xliff:g id="COUNT">^1</xliff:g> аўдыяфайлаў перамяшчаюцца са сметніцы…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> аўдыяфайла перамяшчаюцца са сметніцы…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="one">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> відэа са сметніцы?</item>
<item quantity="few">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> відэа са сметніцы?</item>
<item quantity="many">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> відэа са сметніцы?</item>
<item quantity="other">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> відэа са сметніцы?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> відэа перамяшчаецца са сметніцы…</item>
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> відэа перамяшчаюцца са сметніцы…</item>
+ <item quantity="many"><xliff:g id="COUNT">^1</xliff:g> відэа перамяшчаюцца са сметніцы…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> відэа перамяшчаюцца са сметніцы…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="one">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> фота са сметніцы?</item>
<item quantity="few">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> фота са сметніцы?</item>
<item quantity="many">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> фота са сметніцы?</item>
<item quantity="other">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> фота са сметніцы?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> фота перамяшчаецца са сметніцы…</item>
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> фота перамяшчаюцца са сметніцы…</item>
+ <item quantity="many"><xliff:g id="COUNT">^1</xliff:g> фота перамяшчаюцца са сметніцы…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> фота перамяшчаюцца са сметніцы…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="one">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> элемент са сметніцы?</item>
<item quantity="few">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> элементы са сметніцы?</item>
<item quantity="many">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> элементаў са сметніцы?</item>
<item quantity="other">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" перамясціць <xliff:g id="COUNT">^2</xliff:g> элемента са сметніцы?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> элемент перамяшчаецца са сметніцы…</item>
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> элементы перамяшчаюцца са сметніцы…</item>
+ <item quantity="many"><xliff:g id="COUNT">^1</xliff:g> элементаў перамяшчаюцца са сметніцы…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> элемента перамяшчаюцца са сметніцы…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="one">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" выдаліць <xliff:g id="COUNT">^2</xliff:g> аўдыяфайл?</item>
<item quantity="few">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" выдаліць <xliff:g id="COUNT">^2</xliff:g> аўдыяфайлы?</item>
<item quantity="many">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" выдаліць <xliff:g id="COUNT">^2</xliff:g> аўдыяфайлаў?</item>
<item quantity="other">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" выдаліць <xliff:g id="COUNT">^2</xliff:g> аўдыяфайла?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="one">Выдаляецца <xliff:g id="COUNT">^1</xliff:g> аўдыяфайл…</item>
+ <item quantity="few">Выдаляюцца <xliff:g id="COUNT">^1</xliff:g> аўдыяфайлы…</item>
+ <item quantity="many">Выдаляюцца <xliff:g id="COUNT">^1</xliff:g> аўдыяфайлаў…</item>
+ <item quantity="other">Выдаляюцца <xliff:g id="COUNT">^1</xliff:g> аўдыяфайла…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="one">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" выдаліць <xliff:g id="COUNT">^2</xliff:g> відэа?</item>
<item quantity="few">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" выдаліць <xliff:g id="COUNT">^2</xliff:g> відэа?</item>
<item quantity="many">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" выдаліць <xliff:g id="COUNT">^2</xliff:g> відэа?</item>
<item quantity="other">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" выдаліць <xliff:g id="COUNT">^2</xliff:g> відэа?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="one">Выдаляецца <xliff:g id="COUNT">^1</xliff:g> відэа…</item>
+ <item quantity="few">Выдаляюцца <xliff:g id="COUNT">^1</xliff:g> відэа…</item>
+ <item quantity="many">Выдаляюцца <xliff:g id="COUNT">^1</xliff:g> відэа…</item>
+ <item quantity="other">Выдаляюцца <xliff:g id="COUNT">^1</xliff:g> відэа…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="one">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" выдаліць <xliff:g id="COUNT">^2</xliff:g> фота?</item>
<item quantity="few">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" выдаліць <xliff:g id="COUNT">^2</xliff:g> фота?</item>
<item quantity="many">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" выдаліць <xliff:g id="COUNT">^2</xliff:g> фота?</item>
<item quantity="other">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" выдаліць <xliff:g id="COUNT">^2</xliff:g> фота?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="one">Выдаляецца <xliff:g id="COUNT">^1</xliff:g> фота…</item>
+ <item quantity="few">Выдаляюцца <xliff:g id="COUNT">^1</xliff:g> фота…</item>
+ <item quantity="many">Выдаляюцца <xliff:g id="COUNT">^1</xliff:g> фота…</item>
+ <item quantity="other">Выдаляюцца <xliff:g id="COUNT">^1</xliff:g> фота…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="one">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" выдаліць <xliff:g id="COUNT">^2</xliff:g> элемент?</item>
<item quantity="few">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" выдаліць <xliff:g id="COUNT">^2</xliff:g> элементы?</item>
<item quantity="many">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" выдаліць <xliff:g id="COUNT">^2</xliff:g> элементаў?</item>
<item quantity="other">Дазволіць праграме \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" выдаліць <xliff:g id="COUNT">^2</xliff:g> элемента?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="one">Выдаляецца <xliff:g id="COUNT">^1</xliff:g> элемент…</item>
+ <item quantity="few">Выдаляюцца <xliff:g id="COUNT">^1</xliff:g> элементы…</item>
+ <item quantity="many">Выдаляюцца <xliff:g id="COUNT">^1</xliff:g> элементаў…</item>
+ <item quantity="other">Выдаляюцца <xliff:g id="COUNT">^1</xliff:g> элемента…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"Праграме \"<xliff:g id="APP_NAME">%s</xliff:g>\" не ўдалося апрацаваць файлы мультымедыя"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Апрацоўка мультымедыя скасавана"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Памылка апрацоўкі мультымедыя"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Апрацоўка мультымедыя завершана"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Пачалася апрацоўка мультымедыя"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Ідзе апрацоўка мультымедыя…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Скасаваць"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Пачакаць"</string>
</resources>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index b576228..878ad13 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">Да се разреши ли на <xliff:g id="APP_NAME_1">^1</xliff:g> да промени <xliff:g id="COUNT">^2</xliff:g> аудиофайла?</item>
<item quantity="one">Да се разреши ли на <xliff:g id="APP_NAME_0">^1</xliff:g> да промени този аудиофайл?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> аудиофайла се променят…</item>
+ <item quantity="one">Аудиофайлът се променя…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">Да се разреши ли на <xliff:g id="APP_NAME_1">^1</xliff:g> да промени <xliff:g id="COUNT">^2</xliff:g> видеоклипа?</item>
<item quantity="one">Да се разреши ли на <xliff:g id="APP_NAME_0">^1</xliff:g> да промени този видеоклип?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> видеоклипа се променят…</item>
+ <item quantity="one">Видеоклипът се променя…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">Да се разреши ли на <xliff:g id="APP_NAME_1">^1</xliff:g> да промени <xliff:g id="COUNT">^2</xliff:g> снимки?</item>
<item quantity="one">Да се разреши ли на <xliff:g id="APP_NAME_0">^1</xliff:g> да промени тази снимка?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> снимки се променят…</item>
+ <item quantity="one">Снимката се променя…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">Да се разреши ли на <xliff:g id="APP_NAME_1">^1</xliff:g> да промени <xliff:g id="COUNT">^2</xliff:g> елемента?</item>
<item quantity="one">Да се разреши ли на <xliff:g id="APP_NAME_0">^1</xliff:g> да промени този елемент?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> елемента се променят…</item>
+ <item quantity="one">Елементът се променя…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">Да се разреши ли на <xliff:g id="APP_NAME_1">^1</xliff:g> да премести <xliff:g id="COUNT">^2</xliff:g> аудиофайла в кошчето?</item>
<item quantity="one">Да се разреши ли на <xliff:g id="APP_NAME_0">^1</xliff:g> да премести този аудиофайл в кошчето?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> аудиофайла се преместват в кошчето…</item>
+ <item quantity="one">Аудиофайлът се премества в кошчето…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">Да се разреши ли на <xliff:g id="APP_NAME_1">^1</xliff:g> да премести <xliff:g id="COUNT">^2</xliff:g> видеоклипа в кошчето?</item>
<item quantity="one">Да се разреши ли на <xliff:g id="APP_NAME_0">^1</xliff:g> да премести този видеоклип в кошчето?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> видеоклипа се преместват в кошчето…</item>
+ <item quantity="one">Видеоклипът се премества в кошчето…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">Да се разреши ли на <xliff:g id="APP_NAME_1">^1</xliff:g> да премести <xliff:g id="COUNT">^2</xliff:g> снимки в кошчето?</item>
<item quantity="one">Да се разреши ли на <xliff:g id="APP_NAME_0">^1</xliff:g> да премести тази снимка в кошчето?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> снимки се преместват в кошчето…</item>
+ <item quantity="one">Снимката се премества в кошчето…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">Да се разреши ли на <xliff:g id="APP_NAME_1">^1</xliff:g> да премести <xliff:g id="COUNT">^2</xliff:g> елемента в кошчето?</item>
<item quantity="one">Да се разреши ли на <xliff:g id="APP_NAME_0">^1</xliff:g> да премести този елемент в кошчето?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> елемента се преместват в кошчето…</item>
+ <item quantity="one">Елементът се премества в кошчето…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">Да се разреши ли на <xliff:g id="APP_NAME_1">^1</xliff:g> да премести <xliff:g id="COUNT">^2</xliff:g> аудиофайла извън кошчето?</item>
<item quantity="one">Да се разреши ли на <xliff:g id="APP_NAME_0">^1</xliff:g> да премести този аудиофайл извън кошчето?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> аудиофайла се преместват извън кошчето…</item>
+ <item quantity="one">Аудиофайлът се премества извън кошчето…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">Да се разреши ли на <xliff:g id="APP_NAME_1">^1</xliff:g> да премести <xliff:g id="COUNT">^2</xliff:g> видеоклипа извън кошчето?</item>
<item quantity="one">Да се разреши ли на <xliff:g id="APP_NAME_0">^1</xliff:g> да премести този видеоклип извън кошчето?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> видеоклипа се преместват извън кошчето…</item>
+ <item quantity="one">Видеоклипът се премества извън кошчето…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">Да се разреши ли на <xliff:g id="APP_NAME_1">^1</xliff:g> да премести <xliff:g id="COUNT">^2</xliff:g> снимки извън кошчето?</item>
<item quantity="one">Да се разреши ли на <xliff:g id="APP_NAME_0">^1</xliff:g> да премести тази снимка извън кошчето?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> снимки се преместват извън кошчето…</item>
+ <item quantity="one">Снимката се премества извън кошчето…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">Да се разреши ли на <xliff:g id="APP_NAME_1">^1</xliff:g> да премести <xliff:g id="COUNT">^2</xliff:g> елемента извън кошчето?</item>
<item quantity="one">Да се разреши ли на <xliff:g id="APP_NAME_0">^1</xliff:g> да премести този елемент извън кошчето?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> елемента се преместват извън кошчето…</item>
+ <item quantity="one">Елементът се премества извън кошчето…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">Да се разреши ли на <xliff:g id="APP_NAME_1">^1</xliff:g> да изтрие <xliff:g id="COUNT">^2</xliff:g> аудиофайла?</item>
<item quantity="one">Да се разреши ли на <xliff:g id="APP_NAME_0">^1</xliff:g> да изтрие този аудиофайл?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> аудиофайла се изтриват…</item>
+ <item quantity="one">Аудиофайлът се изтрива…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">Да се разреши ли на <xliff:g id="APP_NAME_1">^1</xliff:g> да изтрие <xliff:g id="COUNT">^2</xliff:g> видеоклипа?</item>
<item quantity="one">Да се разреши ли на <xliff:g id="APP_NAME_0">^1</xliff:g> да изтрие този видеоклип?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> видеоклипа се изтриват…</item>
+ <item quantity="one">Видеоклипът се изтрива…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">Да се разреши ли на <xliff:g id="APP_NAME_1">^1</xliff:g> да изтрие <xliff:g id="COUNT">^2</xliff:g> снимки?</item>
<item quantity="one">Да се разреши ли на <xliff:g id="APP_NAME_0">^1</xliff:g> да изтрие тази снимка?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> снимки се изтриват…</item>
+ <item quantity="one">Снимката се изтрива…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">Да се разреши ли на <xliff:g id="APP_NAME_1">^1</xliff:g> да изтрие <xliff:g id="COUNT">^2</xliff:g> елемента?</item>
<item quantity="one">Да се разреши ли на <xliff:g id="APP_NAME_0">^1</xliff:g> да изтрие този елемент?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> елемента се изтриват…</item>
+ <item quantity="one">Елементът се изтрива…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> не може да обработва мултимедийни файлове"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Обработването на мултимедията е анулирано"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Грешка при обработването на мултимедията"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Обработването на мултимедията бе успешно"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Обработването на мултимедията стартира"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Мултимедията се обработва…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Отказ"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Изчакване"</string>
</resources>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 4b02f68..06b23e7 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -47,64 +47,136 @@
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি অডিও ফাইল পরিবর্তন করার অনুমতি দিতে চান?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি অডিও ফাইল পরিবর্তন করার অনুমতি দিতে চান?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g>টি অডিও ফাইল পরিবর্তন করা হচ্ছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>টি অডিও ফাইল পরিবর্তন করা হচ্ছে…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি ভিডিও পরিবর্তন করার অনুমতি দিতে চান?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি ভিডিও পরিবর্তন করার অনুমতি দিতে চান?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g>টি ভিডিও পরিবর্তন করা হচ্ছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>টি ভিডিও পরিবর্তন করা হচ্ছে…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি ফটো পরিবর্তন করার অনুমতি দিতে চান?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি ফটো পরিবর্তন করার অনুমতি দিতে চান?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g>টি ফটোতে পরিবর্তন করা হচ্ছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>টি ফটোতে পরিবর্তন করা হচ্ছে…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি আইটেম পরিবর্তন করার অনুমতি দিতে চান?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি আইটেম পরিবর্তন করার অনুমতি দিতে চান?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g>টি আইটেম পরিবর্তন করা হচ্ছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>টি আইটেম পরিবর্তন করা হচ্ছে…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি অডিও ফাইল ট্র্যাশ ফোল্ডারে সরিয়ে দেওয়ার অনুমতি দিতে চান?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি অডিও ফাইল ট্র্যাশ ফোল্ডারে সরিয়ে দেওয়ার অনুমতি দিতে চান?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g>টি অডিও ফাইল ট্র্যাশে সরানো হচ্ছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>টি অডিও ফাইল ট্র্যাশে সরানো হচ্ছে…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি ভিডিও ট্র্যাশ ফোল্ডারে সরিয়ে দেওয়ার অনুমতি দিতে চান?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি ভিডিও ট্র্যাশ ফোল্ডারে সরিয়ে দেওয়ার অনুমতি দিতে চান?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g>টি ভিডিও ট্র্যাশে সরানো হচ্ছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>টি ভিডিও ট্র্যাশে সরানো হচ্ছে…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি ফটো ট্র্যাশ ফোল্ডারে সরিয়ে দেওয়ার অনুমতি দিতে চান?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি ফটো ট্র্যাশ ফোল্ডারে সরিয়ে দেওয়ার অনুমতি দিতে চান?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g>টি ফটো ট্র্যাশে সরানো হচ্ছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>টি ফটো ট্র্যাশে সরানো হচ্ছে…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি আইটেম ট্র্যাশ ফোল্ডারে সরিয়ে দেওয়ার অনুমতি দিতে চান?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি আইটেম ট্র্যাশ ফোল্ডারে সরিয়ে দেওয়ার অনুমতি দিতে চান?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g>টি আইটেম ট্র্যাশে সরানো হচ্ছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>টি আইটেম ট্র্যাশে সরানো হচ্ছে…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি অডিও ফাইল ট্র্যাশ ফোল্ডার থেকে সরানোর অনুমতি দিতে চান?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি অডিও ফাইল ট্র্যাশ ফোল্ডার থেকে সরানোর অনুমতি দিতে চান?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g>টি অডিও ফাইলকে ট্র্যাশ থেকে বের করে আনা হচ্ছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>টি অডিও ফাইলকে ট্র্যাশ থেকে বের করে আনা হচ্ছে…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি ভিডিও ট্র্যাশ ফোল্ডার থেকে সরানোর অনুমতি দিতে চান?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি ভিডিও ট্র্যাশ ফোল্ডার থেকে সরানোর অনুমতি দিতে চান?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g>টি ভিডিওকে ট্র্যাশ থেকে বের করে আনা হচ্ছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>টি ভিডিওকে ট্র্যাশ থেকে বের করে আনা হচ্ছে…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি ফটো ট্র্যাশ ফোল্ডার থেকে সরানোর অনুমতি দিতে চান?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি ফটো ট্র্যাশ ফোল্ডার থেকে সরানোর অনুমতি দিতে চান?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g>টি ফটোকে ট্র্যাশ থেকে বের করে আনা হচ্ছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>টি ফটোকে ট্র্যাশ থেকে বের করে আনা হচ্ছে…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি আইটেম ট্র্যাশ ফোল্ডার থেকে সরানোর অনুমতি দিতে চান?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি আইটেম ট্র্যাশ ফোল্ডার থেকে সরানোর অনুমতি দিতে চান?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g>টি আইটেমকে ট্র্যাশ থেকে বের করে আনা হচ্ছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>টি আইটেমকে ট্র্যাশ থেকে বের করে আনা হচ্ছে…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি অডিও ফাইল মুছে দেওয়ার অনুমতি দিতে চান?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি অডিও ফাইল মুছে দেওয়ার অনুমতি দিতে চান?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g>টি অডিও ফাইল মুছে ফেলা হচ্ছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>টি অডিও ফাইল মুছে ফেলা হচ্ছে…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি ভিডিও মুছে দেওয়ার অনুমতি দিতে চান?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি ভিডিও মুছে দেওয়ার অনুমতি দিতে চান?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g>টি ভিডিও মুছে ফেলা হচ্ছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>টি ভিডিও মুছে ফেলা হচ্ছে…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি ফটো মুছে দেওয়ার অনুমতি দিতে চান?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি ফটো মুছে দেওয়ার অনুমতি দিতে চান?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g>টি ফটো মুছে ফেলা হচ্ছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>টি ফটো মুছে ফেলা হচ্ছে…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি আইটেম মুছে দেওয়ার অনুমতি দিতে চান?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-কে <xliff:g id="COUNT">^2</xliff:g>টি আইটেম মুছে দেওয়ার অনুমতি দিতে চান?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g>টি আইটেম মুছে ফেলা হচ্ছে…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>টি আইটেম মুছে ফেলা হচ্ছে…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> মিডিয়া ফাইল প্রসেস করতে পারবে না"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"মিডিয়া ফাইল প্রসেস করা বাতিল হয়ে গেছে"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"মিডিয়া ফাইল প্রসেস করার সময়ে সমস্যা হচ্ছে"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"মিডিয়া ফাইল প্রসেস করা হয়ে গেছে"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"মিডিয়া ফাইল প্রসেস করা শুরু হয়ে গেছে"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"মিডিয়া ফাইল প্রসেস করা হচ্ছে…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"বাতিল করুন"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"অপেক্ষা করুন"</string>
</resources>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 9f89481..791b3a4 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -50,79 +50,167 @@
<item quantity="few">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> izmijeni <xliff:g id="COUNT">^2</xliff:g> audio fajla?</item>
<item quantity="other">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> izmijeni <xliff:g id="COUNT">^2</xliff:g> audio fajlova?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="one">Mijenjanje <xliff:g id="COUNT">^1</xliff:g> audio fajla…</item>
+ <item quantity="few">Mijenjanje <xliff:g id="COUNT">^1</xliff:g> audio fajla…</item>
+ <item quantity="other">Mijenjanje <xliff:g id="COUNT">^1</xliff:g> audio fajlova…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="one">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> izmijeni <xliff:g id="COUNT">^2</xliff:g> videozapis?</item>
<item quantity="few">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> izmijeni <xliff:g id="COUNT">^2</xliff:g> videozapisa?</item>
<item quantity="other">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> izmijeni <xliff:g id="COUNT">^2</xliff:g> videozapisa?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="one">Mijenjanje <xliff:g id="COUNT">^1</xliff:g> videozapisa…</item>
+ <item quantity="few">Mijenjanje <xliff:g id="COUNT">^1</xliff:g> videozapisa…</item>
+ <item quantity="other">Mijenjanje <xliff:g id="COUNT">^1</xliff:g> videozapisa…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="one">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> izmijeni <xliff:g id="COUNT">^2</xliff:g> fotografiju?</item>
<item quantity="few">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> izmijeni <xliff:g id="COUNT">^2</xliff:g> fotografije?</item>
<item quantity="other">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> izmijeni <xliff:g id="COUNT">^2</xliff:g> fotografija?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="one">Mijenjanje <xliff:g id="COUNT">^1</xliff:g> fotografije…</item>
+ <item quantity="few">Mijenjanje <xliff:g id="COUNT">^1</xliff:g> fotografije…</item>
+ <item quantity="other">Mijenjanje <xliff:g id="COUNT">^1</xliff:g> fotografija…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="one">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> izmijeni <xliff:g id="COUNT">^2</xliff:g> stavku?</item>
<item quantity="few">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> izmijeni <xliff:g id="COUNT">^2</xliff:g> stavke?</item>
<item quantity="other">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> izmijeni <xliff:g id="COUNT">^2</xliff:g> stavki?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="one">Mijenjanje <xliff:g id="COUNT">^1</xliff:g> stavke…</item>
+ <item quantity="few">Mijenjanje <xliff:g id="COUNT">^1</xliff:g> stavke…</item>
+ <item quantity="other">Mijenjanje <xliff:g id="COUNT">^1</xliff:g> stavki…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="one">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> premjesti <xliff:g id="COUNT">^2</xliff:g> audio fajl u otpad?</item>
<item quantity="few">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> premjesti <xliff:g id="COUNT">^2</xliff:g> audio fajla u otpad?</item>
<item quantity="other">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> premjesti <xliff:g id="COUNT">^2</xliff:g> audio fajlova u otpad?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="one">Premještanje <xliff:g id="COUNT">^1</xliff:g> audio fajla u otpad…</item>
+ <item quantity="few">Premještanje <xliff:g id="COUNT">^1</xliff:g> audio fajla u otpad…</item>
+ <item quantity="other">Premještanje <xliff:g id="COUNT">^1</xliff:g> audio fajlova u otpad…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="one">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> premjesti <xliff:g id="COUNT">^2</xliff:g> videozapis u otpad?</item>
<item quantity="few">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> premjesti <xliff:g id="COUNT">^2</xliff:g> videozapisa u otpad?</item>
<item quantity="other">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> premjesti <xliff:g id="COUNT">^2</xliff:g> videozapisa u otpad?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="one">Premještanje <xliff:g id="COUNT">^1</xliff:g> videozapisa u otpad…</item>
+ <item quantity="few">Premještanje <xliff:g id="COUNT">^1</xliff:g> videozapisa u otpad…</item>
+ <item quantity="other">Premještanje <xliff:g id="COUNT">^1</xliff:g> videozapisa u otpad…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="one">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> premjesti <xliff:g id="COUNT">^2</xliff:g> fotografiju u otpad?</item>
<item quantity="few">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> premjesti <xliff:g id="COUNT">^2</xliff:g> fotografije u otpad?</item>
<item quantity="other">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> premjesti <xliff:g id="COUNT">^2</xliff:g> fotografija u otpad?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="one">Premještanje <xliff:g id="COUNT">^1</xliff:g> fotografije u otpad…</item>
+ <item quantity="few">Premještanje <xliff:g id="COUNT">^1</xliff:g> fotografije u otpad…</item>
+ <item quantity="other">Premještanje <xliff:g id="COUNT">^1</xliff:g> fotografija u otpad…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="one">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> premjesti <xliff:g id="COUNT">^2</xliff:g> stavku u otpad?</item>
<item quantity="few">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> premjesti <xliff:g id="COUNT">^2</xliff:g> stavke u otpad?</item>
<item quantity="other">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> premjesti <xliff:g id="COUNT">^2</xliff:g> stavki u otpad?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="one">Premještanje <xliff:g id="COUNT">^1</xliff:g> stavke u otpad…</item>
+ <item quantity="few">Premještanje <xliff:g id="COUNT">^1</xliff:g> stavke u otpad…</item>
+ <item quantity="other">Premještanje <xliff:g id="COUNT">^1</xliff:g> stavki u otpad…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="one">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> premjesti <xliff:g id="COUNT">^2</xliff:g> audio fajl iz otpada?</item>
<item quantity="few">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> premjesti <xliff:g id="COUNT">^2</xliff:g> audio fajla iz otpada?</item>
<item quantity="other">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> premjesti <xliff:g id="COUNT">^2</xliff:g> audio fajlova iz otpada?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="one">Premještanje <xliff:g id="COUNT">^1</xliff:g> audio fajla iz otpada…</item>
+ <item quantity="few">Premještanje <xliff:g id="COUNT">^1</xliff:g> audio fajla iz otpada…</item>
+ <item quantity="other">Premještanje <xliff:g id="COUNT">^1</xliff:g> audio fajlova iz otpada…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="one">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> premjesti <xliff:g id="COUNT">^2</xliff:g> videozapis iz otpada?</item>
<item quantity="few">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> premjesti <xliff:g id="COUNT">^2</xliff:g> videozapisa iz otpada?</item>
<item quantity="other">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> premjesti <xliff:g id="COUNT">^2</xliff:g> videozapisa iz otpada?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="one">Premještanje <xliff:g id="COUNT">^1</xliff:g> videozapisa iz otpada…</item>
+ <item quantity="few">Premještanje <xliff:g id="COUNT">^1</xliff:g> videozapisa iz otpada…</item>
+ <item quantity="other">Premještanje <xliff:g id="COUNT">^1</xliff:g> videozapisa iz otpada…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="one">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> premjesti <xliff:g id="COUNT">^2</xliff:g> fotografiju iz otpada?</item>
<item quantity="few">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> premjesti <xliff:g id="COUNT">^2</xliff:g> fotografije iz otpada?</item>
<item quantity="other">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> premjesti <xliff:g id="COUNT">^2</xliff:g> fotografija iz otpada?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="one">Premještanje <xliff:g id="COUNT">^1</xliff:g> fotografije iz otpada…</item>
+ <item quantity="few">Premještanje <xliff:g id="COUNT">^1</xliff:g> fotografije iz otpada…</item>
+ <item quantity="other">Premještanje <xliff:g id="COUNT">^1</xliff:g> fotografija iz otpada…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="one">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> premjesti <xliff:g id="COUNT">^2</xliff:g> stavku iz otpada?</item>
<item quantity="few">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> premjesti <xliff:g id="COUNT">^2</xliff:g> stavke iz otpada?</item>
<item quantity="other">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> premjesti <xliff:g id="COUNT">^2</xliff:g> stavki iz otpada?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="one">Premještanje <xliff:g id="COUNT">^1</xliff:g> stavke iz otpada…</item>
+ <item quantity="few">Premještanje <xliff:g id="COUNT">^1</xliff:g> stavke iz otpada…</item>
+ <item quantity="other">Premještanje <xliff:g id="COUNT">^1</xliff:g> stavki iz otpada…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="one">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> izbriše <xliff:g id="COUNT">^2</xliff:g> audio fajl?</item>
<item quantity="few">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> izbriše <xliff:g id="COUNT">^2</xliff:g> audio fajla?</item>
<item quantity="other">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> izbriše <xliff:g id="COUNT">^2</xliff:g> audio fajlova?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="one">Brisanje <xliff:g id="COUNT">^1</xliff:g> audio fajla…</item>
+ <item quantity="few">Brisanje <xliff:g id="COUNT">^1</xliff:g> audio fajla…</item>
+ <item quantity="other">Brisanje <xliff:g id="COUNT">^1</xliff:g> audio fajlova…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="one">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> izbriše <xliff:g id="COUNT">^2</xliff:g> videozapis?</item>
<item quantity="few">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> izbriše <xliff:g id="COUNT">^2</xliff:g> videozapisa?</item>
<item quantity="other">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> izbriše <xliff:g id="COUNT">^2</xliff:g> videozapisa?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="one">Brisanje <xliff:g id="COUNT">^1</xliff:g> videozapisa…</item>
+ <item quantity="few">Brisanje <xliff:g id="COUNT">^1</xliff:g> videozapisa…</item>
+ <item quantity="other">Brisanje <xliff:g id="COUNT">^1</xliff:g> videozapisa…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="one">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> izbriše <xliff:g id="COUNT">^2</xliff:g> fotografiju?</item>
<item quantity="few">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> izbriše <xliff:g id="COUNT">^2</xliff:g> fotografije?</item>
<item quantity="other">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> izbriše <xliff:g id="COUNT">^2</xliff:g> fotografija?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="one">Brisanje <xliff:g id="COUNT">^1</xliff:g> fotografije…</item>
+ <item quantity="few">Brisanje <xliff:g id="COUNT">^1</xliff:g> fotografije…</item>
+ <item quantity="other">Brisanje <xliff:g id="COUNT">^1</xliff:g> fotografija…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="one">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> izbriše <xliff:g id="COUNT">^2</xliff:g> stavku?</item>
<item quantity="few">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> izbriše <xliff:g id="COUNT">^2</xliff:g> stavke?</item>
<item quantity="other">Dozvoliti da <xliff:g id="APP_NAME_1">^1</xliff:g> izbriše <xliff:g id="COUNT">^2</xliff:g> stavki?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="one">Brisanje <xliff:g id="COUNT">^1</xliff:g> stavke…</item>
+ <item quantity="few">Brisanje <xliff:g id="COUNT">^1</xliff:g> stavke…</item>
+ <item quantity="other">Brisanje <xliff:g id="COUNT">^1</xliff:g> stavki…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> ne može obrađivati medijske fajlove"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Obrada medijskih fajlova je otkazana"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Greška prilikom obrade medijskih fajlova"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Obrada medijskih fajlova je uspjela"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Obrada medijskih fajlova je započeta"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Obrada medijskih fajlova…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Otkaži"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Sačekaj"</string>
</resources>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 184a9b9..9341998 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">Vols permetre que <xliff:g id="APP_NAME_1">^1</xliff:g> modifiqui <xliff:g id="COUNT">^2</xliff:g> fitxers d\'àudio?</item>
<item quantity="one">Vols permetre que <xliff:g id="APP_NAME_0">^1</xliff:g> modifiqui aquest fitxer d\'àudio?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other">S\'estan modificant <xliff:g id="COUNT">^1</xliff:g> fitxers d\'àudio…</item>
+ <item quantity="one">S\'està modificant el fitxer d\'àudio…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">Vols permetre que <xliff:g id="APP_NAME_1">^1</xliff:g> modifiqui <xliff:g id="COUNT">^2</xliff:g> vídeos?</item>
<item quantity="one">Vols permetre que <xliff:g id="APP_NAME_0">^1</xliff:g> modifiqui aquest vídeo?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other">S\'estan modificant <xliff:g id="COUNT">^1</xliff:g> vídeos…</item>
+ <item quantity="one">S\'està modificant el vídeo…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">Vols permetre que <xliff:g id="APP_NAME_1">^1</xliff:g> modifiqui <xliff:g id="COUNT">^2</xliff:g> fotos?</item>
<item quantity="one">Vols permetre que <xliff:g id="APP_NAME_0">^1</xliff:g> modifiqui aquesta foto?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other">S\'estan modificant <xliff:g id="COUNT">^1</xliff:g> fotos…</item>
+ <item quantity="one">S\'està modificant la foto…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">Vols permetre que <xliff:g id="APP_NAME_1">^1</xliff:g> modifiqui <xliff:g id="COUNT">^2</xliff:g> elements?</item>
<item quantity="one">Vols permetre que <xliff:g id="APP_NAME_0">^1</xliff:g> modifiqui aquest element?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other">S\'estan modificant <xliff:g id="COUNT">^1</xliff:g> elements…</item>
+ <item quantity="one">S\'està modificant l\'element…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">Vols permetre que <xliff:g id="APP_NAME_1">^1</xliff:g> mogui <xliff:g id="COUNT">^2</xliff:g> fitxers d\'àudio a la paperera?</item>
<item quantity="one">Vols permetre que <xliff:g id="APP_NAME_0">^1</xliff:g> mogui aquest fitxer d\'àudio a la paperera?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other">S\'estan movent <xliff:g id="COUNT">^1</xliff:g> fitxers d\'àudio a la paperera…</item>
+ <item quantity="one">S\'està movent el fitxer d\'àudio a la paperera…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">Vols permetre que <xliff:g id="APP_NAME_1">^1</xliff:g> mogui <xliff:g id="COUNT">^2</xliff:g> vídeos a la paperera?</item>
<item quantity="one">Vols permetre que <xliff:g id="APP_NAME_0">^1</xliff:g> mogui aquest vídeo a la paperera?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other">S\'estan movent <xliff:g id="COUNT">^1</xliff:g> vídeos a la paperera…</item>
+ <item quantity="one">S\'està movent el vídeo a la paperera…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">Vols permetre que <xliff:g id="APP_NAME_1">^1</xliff:g> mogui <xliff:g id="COUNT">^2</xliff:g> fotos a la paperera?</item>
<item quantity="one">Vols permetre que <xliff:g id="APP_NAME_0">^1</xliff:g> mogui aquesta foto a la paperera?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other">S\'estan movent <xliff:g id="COUNT">^1</xliff:g> fotos a la paperera…</item>
+ <item quantity="one">S\'està movent la foto a la paperera…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">Vols permetre que <xliff:g id="APP_NAME_1">^1</xliff:g> mogui <xliff:g id="COUNT">^2</xliff:g> elements a la paperera?</item>
<item quantity="one">Vols permetre que <xliff:g id="APP_NAME_0">^1</xliff:g> mogui aquest element a la paperera?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other">S\'estan movent <xliff:g id="COUNT">^1</xliff:g> elements a la paperera…</item>
+ <item quantity="one">S\'està movent l\'element a la paperera…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">Vols permetre que <xliff:g id="APP_NAME_1">^1</xliff:g> tregui <xliff:g id="COUNT">^2</xliff:g> fitxers d\'àudio de la paperera?</item>
<item quantity="one">Vols permetre que <xliff:g id="APP_NAME_0">^1</xliff:g> tregui aquest fitxer d\'àudio de la paperera?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other">S\'estan traient <xliff:g id="COUNT">^1</xliff:g> fitxers d\'àudio de la paperera…</item>
+ <item quantity="one">S\'està traient el fitxer d\'àudio de la paperera…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">Vols permetre que <xliff:g id="APP_NAME_1">^1</xliff:g> tregui <xliff:g id="COUNT">^2</xliff:g> vídeos de la paperera?</item>
<item quantity="one">Vols permetre que <xliff:g id="APP_NAME_0">^1</xliff:g> tregui aquest vídeo de la paperera?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other">S\'estan traient <xliff:g id="COUNT">^1</xliff:g> vídeos de la paperera…</item>
+ <item quantity="one">S\'està traient el vídeo de la paperera…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">Vols permetre que <xliff:g id="APP_NAME_1">^1</xliff:g> tregui <xliff:g id="COUNT">^2</xliff:g> fotos de la paperera?</item>
<item quantity="one">Vols permetre que <xliff:g id="APP_NAME_0">^1</xliff:g> tregui aquesta foto de la paperera?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other">S\'estan traient <xliff:g id="COUNT">^1</xliff:g> fotos de la paperera…</item>
+ <item quantity="one">S\'està traient la foto de la paperera…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">Vols permetre que <xliff:g id="APP_NAME_1">^1</xliff:g> tregui <xliff:g id="COUNT">^2</xliff:g> elements de la paperera?</item>
<item quantity="one">Vols permetre que <xliff:g id="APP_NAME_0">^1</xliff:g> tregui aquest element de la paperera?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other">S\'estan traient <xliff:g id="COUNT">^1</xliff:g> elements de la paperera…</item>
+ <item quantity="one">S\'està traient l\'element de la paperera…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">Vols permetre que <xliff:g id="APP_NAME_1">^1</xliff:g> suprimeixi <xliff:g id="COUNT">^2</xliff:g> fitxers d\'àudio?</item>
<item quantity="one">Vols permetre que <xliff:g id="APP_NAME_0">^1</xliff:g> suprimeixi aquest fitxer d\'àudio?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other">S\'estan suprimint <xliff:g id="COUNT">^1</xliff:g> fitxers d\'àudio…</item>
+ <item quantity="one">S\'està suprimint el fitxer d\'àudio…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">Vols permetre que <xliff:g id="APP_NAME_1">^1</xliff:g> suprimeixi <xliff:g id="COUNT">^2</xliff:g> vídeos?</item>
<item quantity="one">Vols permetre que <xliff:g id="APP_NAME_0">^1</xliff:g> suprimeixi aquest vídeo?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other">S\'estan suprimint <xliff:g id="COUNT">^1</xliff:g> vídeos…</item>
+ <item quantity="one">S\'està suprimint el vídeo…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">Vols permetre que <xliff:g id="APP_NAME_1">^1</xliff:g> suprimeixi <xliff:g id="COUNT">^2</xliff:g> fotos?</item>
<item quantity="one">Vols permetre que <xliff:g id="APP_NAME_0">^1</xliff:g> suprimeixi aquesta foto?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other">S\'estan suprimint <xliff:g id="COUNT">^1</xliff:g> fotos…</item>
+ <item quantity="one">S\'està suprimint la foto…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">Vols permetre que <xliff:g id="APP_NAME_1">^1</xliff:g> suprimeixi <xliff:g id="COUNT">^2</xliff:g> elements?</item>
<item quantity="one">Vols permetre que <xliff:g id="APP_NAME_0">^1</xliff:g> suprimeixi aquest element?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other">S\'estan suprimint <xliff:g id="COUNT">^1</xliff:g> elements…</item>
+ <item quantity="one">S\'està suprimint l\'element…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> no pot processar els fitxers multimèdia"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"El processament del contingut multimèdia s\'ha cancel·lat"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"S\'ha produït un error en processar el contingut multimèdia"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"El contingut multimèdia s\'ha processat correctament"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"El processament del contingut multimèdia s\'ha iniciat"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"S\'està processant el contingut multimèdia…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Cancel·la"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Espera"</string>
</resources>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 3fa3e40..eab7293 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -53,94 +53,198 @@
<item quantity="other">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> upravit <xliff:g id="COUNT">^2</xliff:g> zvukových souborů?</item>
<item quantity="one">Povolit aplikaci <xliff:g id="APP_NAME_0">^1</xliff:g> upravit tento zvukový soubor?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="few">Úprava <xliff:g id="COUNT">^1</xliff:g> zvukových souborů…</item>
+ <item quantity="many">Úprava <xliff:g id="COUNT">^1</xliff:g> zvukového souboru…</item>
+ <item quantity="other">Úprava <xliff:g id="COUNT">^1</xliff:g> zvukových souborů…</item>
+ <item quantity="one">Úprava zvukového souboru…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="few">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> upravit <xliff:g id="COUNT">^2</xliff:g> videa?</item>
<item quantity="many">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> upravit <xliff:g id="COUNT">^2</xliff:g> videa?</item>
<item quantity="other">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> upravit <xliff:g id="COUNT">^2</xliff:g> videí?</item>
<item quantity="one">Povolit aplikaci <xliff:g id="APP_NAME_0">^1</xliff:g> upravit toto video?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="few">Úprava <xliff:g id="COUNT">^1</xliff:g> videí…</item>
+ <item quantity="many">Úprava <xliff:g id="COUNT">^1</xliff:g> videa…</item>
+ <item quantity="other">Úprava <xliff:g id="COUNT">^1</xliff:g> videí…</item>
+ <item quantity="one">Úprava videa…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="few">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> upravit <xliff:g id="COUNT">^2</xliff:g> fotky?</item>
<item quantity="many">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> upravit <xliff:g id="COUNT">^2</xliff:g> fotky?</item>
<item quantity="other">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> upravit <xliff:g id="COUNT">^2</xliff:g> fotek?</item>
<item quantity="one">Povolit aplikaci <xliff:g id="APP_NAME_0">^1</xliff:g> upravit tuto fotku?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="few">Úprava <xliff:g id="COUNT">^1</xliff:g> fotek…</item>
+ <item quantity="many">Úprava <xliff:g id="COUNT">^1</xliff:g> fotky…</item>
+ <item quantity="other">Úprava <xliff:g id="COUNT">^1</xliff:g> fotek…</item>
+ <item quantity="one">Úprava fotky…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="few">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> upravit <xliff:g id="COUNT">^2</xliff:g> položky?</item>
<item quantity="many">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> upravit <xliff:g id="COUNT">^2</xliff:g> položky?</item>
<item quantity="other">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> upravit <xliff:g id="COUNT">^2</xliff:g> položek?</item>
<item quantity="one">Povolit aplikaci <xliff:g id="APP_NAME_0">^1</xliff:g> upravit tuto položku?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="few">Úprava <xliff:g id="COUNT">^1</xliff:g> položek…</item>
+ <item quantity="many">Úprava <xliff:g id="COUNT">^1</xliff:g> položky…</item>
+ <item quantity="other">Úprava <xliff:g id="COUNT">^1</xliff:g> položek…</item>
+ <item quantity="one">Úprava položky…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="few">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> přesunout <xliff:g id="COUNT">^2</xliff:g> zvukové soubory do koše?</item>
<item quantity="many">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> přesunout <xliff:g id="COUNT">^2</xliff:g> zvukového souboru do koše?</item>
<item quantity="other">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> přesunout <xliff:g id="COUNT">^2</xliff:g> zvukových souborů do koše?</item>
<item quantity="one">Povolit aplikaci <xliff:g id="APP_NAME_0">^1</xliff:g> přesunout tento zvukový soubor do koše?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="few">Přesouvání <xliff:g id="COUNT">^1</xliff:g> zvukových souborů do koše…</item>
+ <item quantity="many">Přesouvání <xliff:g id="COUNT">^1</xliff:g> zvukového souboru do koše…</item>
+ <item quantity="other">Přesouvání <xliff:g id="COUNT">^1</xliff:g> zvukových souborů do koše…</item>
+ <item quantity="one">Přesouvání zvukového souboru do koše…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="few">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> přesunout <xliff:g id="COUNT">^2</xliff:g> videa do koše?</item>
<item quantity="many">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> přesunout <xliff:g id="COUNT">^2</xliff:g> videa do koše?</item>
<item quantity="other">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> přesunout <xliff:g id="COUNT">^2</xliff:g> videí do koše?</item>
<item quantity="one">Povolit aplikaci <xliff:g id="APP_NAME_0">^1</xliff:g> přesunout toto video do koše?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="few">Přesouvání <xliff:g id="COUNT">^1</xliff:g> videí do koše…</item>
+ <item quantity="many">Přesouvání <xliff:g id="COUNT">^1</xliff:g> videa do koše…</item>
+ <item quantity="other">Přesouvání <xliff:g id="COUNT">^1</xliff:g> videí do koše…</item>
+ <item quantity="one">Přesouvání videa do koše…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="few">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> přesunout <xliff:g id="COUNT">^2</xliff:g> fotky do koše?</item>
<item quantity="many">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> přesunout <xliff:g id="COUNT">^2</xliff:g> fotky do koše?</item>
<item quantity="other">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> přesunout <xliff:g id="COUNT">^2</xliff:g> fotek do koše?</item>
<item quantity="one">Povolit aplikaci <xliff:g id="APP_NAME_0">^1</xliff:g> přesunout tuto fotku do koše?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="few">Přesouvání <xliff:g id="COUNT">^1</xliff:g> fotek do koše…</item>
+ <item quantity="many">Přesouvání <xliff:g id="COUNT">^1</xliff:g> fotky do koše…</item>
+ <item quantity="other">Přesouvání <xliff:g id="COUNT">^1</xliff:g> fotek do koše…</item>
+ <item quantity="one">Přesouvání fotky do koše…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="few">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> přesunout <xliff:g id="COUNT">^2</xliff:g> položky do koše?</item>
<item quantity="many">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> přesunout <xliff:g id="COUNT">^2</xliff:g> položky do koše?</item>
<item quantity="other">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> přesunout <xliff:g id="COUNT">^2</xliff:g> položek do koše?</item>
<item quantity="one">Povolit aplikaci <xliff:g id="APP_NAME_0">^1</xliff:g> přesunout tuto položku do koše?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="few">Přesouvání <xliff:g id="COUNT">^1</xliff:g> položek do koše…</item>
+ <item quantity="many">Přesouvání <xliff:g id="COUNT">^1</xliff:g> položky do koše…</item>
+ <item quantity="other">Přesouvání <xliff:g id="COUNT">^1</xliff:g> položek do koše…</item>
+ <item quantity="one">Přesouvání položky do koše…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="few">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> vyjmout <xliff:g id="COUNT">^2</xliff:g> zvukové soubory z koše?</item>
<item quantity="many">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> vyjmout <xliff:g id="COUNT">^2</xliff:g> zvukového souboru z koše?</item>
<item quantity="other">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> vyjmout <xliff:g id="COUNT">^2</xliff:g> zvukových souborů z koše?</item>
<item quantity="one">Povolit aplikaci <xliff:g id="APP_NAME_0">^1</xliff:g> vyjmout tento zvukový soubor z koše?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="few">Přesouvání <xliff:g id="COUNT">^1</xliff:g> zvukových souborů z koše…</item>
+ <item quantity="many">Přesouvání <xliff:g id="COUNT">^1</xliff:g> zvukového souboru z koše…</item>
+ <item quantity="other">Přesouvání <xliff:g id="COUNT">^1</xliff:g> zvukových souborů z koše…</item>
+ <item quantity="one">Přesouvání zvukového souboru z koše…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="few">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> vyjmout <xliff:g id="COUNT">^2</xliff:g> videa z koše?</item>
<item quantity="many">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> vyjmout <xliff:g id="COUNT">^2</xliff:g> videa z koše?</item>
<item quantity="other">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> vyjmout <xliff:g id="COUNT">^2</xliff:g> videí z koše?</item>
<item quantity="one">Povolit aplikaci <xliff:g id="APP_NAME_0">^1</xliff:g> vyjmout toto video z koše?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="few">Přesouvání <xliff:g id="COUNT">^1</xliff:g> videí z koše…</item>
+ <item quantity="many">Přesouvání <xliff:g id="COUNT">^1</xliff:g> videa z koše…</item>
+ <item quantity="other">Přesouvání <xliff:g id="COUNT">^1</xliff:g> videí z koše…</item>
+ <item quantity="one">Přesouvání videa z koše…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="few">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> vyjmout <xliff:g id="COUNT">^2</xliff:g> fotky z koše?</item>
<item quantity="many">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> vyjmout <xliff:g id="COUNT">^2</xliff:g> fotky z koše?</item>
<item quantity="other">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> vyjmout <xliff:g id="COUNT">^2</xliff:g> fotek z koše?</item>
<item quantity="one">Povolit aplikaci <xliff:g id="APP_NAME_0">^1</xliff:g> vyjmout tuto fotku z koše?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="few">Přesouvání <xliff:g id="COUNT">^1</xliff:g> fotek z koše…</item>
+ <item quantity="many">Přesouvání <xliff:g id="COUNT">^1</xliff:g> fotky z koše…</item>
+ <item quantity="other">Přesouvání <xliff:g id="COUNT">^1</xliff:g> fotek z koše…</item>
+ <item quantity="one">Přesouvání fotky z koše…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="few">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> vyjmout <xliff:g id="COUNT">^2</xliff:g> položky z koše?</item>
<item quantity="many">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> vyjmout <xliff:g id="COUNT">^2</xliff:g> položky z koše?</item>
<item quantity="other">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> vyjmout <xliff:g id="COUNT">^2</xliff:g> položek z koše?</item>
<item quantity="one">Povolit aplikaci <xliff:g id="APP_NAME_0">^1</xliff:g> vyjmout tuto položku z koše?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="few">Přesouvání <xliff:g id="COUNT">^1</xliff:g> položek z koše…</item>
+ <item quantity="many">Přesouvání <xliff:g id="COUNT">^1</xliff:g> položky z koše…</item>
+ <item quantity="other">Přesouvání <xliff:g id="COUNT">^1</xliff:g> položek z koše…</item>
+ <item quantity="one">Přesouvání položky z koše…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="few">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> smazat <xliff:g id="COUNT">^2</xliff:g> zvukové soubory?</item>
<item quantity="many">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> smazat <xliff:g id="COUNT">^2</xliff:g> zvukového souboru?</item>
<item quantity="other">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> smazat <xliff:g id="COUNT">^2</xliff:g> zvukových souborů?</item>
<item quantity="one">Povolit aplikaci <xliff:g id="APP_NAME_0">^1</xliff:g> smazat tento zvukový soubor?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="few">Mazání <xliff:g id="COUNT">^1</xliff:g> zvukových souborů…</item>
+ <item quantity="many">Mazání <xliff:g id="COUNT">^1</xliff:g> zvukového souboru…</item>
+ <item quantity="other">Mazání <xliff:g id="COUNT">^1</xliff:g> zvukových souborů…</item>
+ <item quantity="one">Mazání zvukového souboru…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="few">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> smazat <xliff:g id="COUNT">^2</xliff:g> videa?</item>
<item quantity="many">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> smazat <xliff:g id="COUNT">^2</xliff:g> videa?</item>
<item quantity="other">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> smazat <xliff:g id="COUNT">^2</xliff:g> videí?</item>
<item quantity="one">Povolit aplikaci <xliff:g id="APP_NAME_0">^1</xliff:g> smazat toto video?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="few">Mazání <xliff:g id="COUNT">^1</xliff:g> videí…</item>
+ <item quantity="many">Mazání <xliff:g id="COUNT">^1</xliff:g> videa…</item>
+ <item quantity="other">Mazání <xliff:g id="COUNT">^1</xliff:g> videí…</item>
+ <item quantity="one">Mazání videa…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="few">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> smazat <xliff:g id="COUNT">^2</xliff:g> fotky?</item>
<item quantity="many">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> smazat <xliff:g id="COUNT">^2</xliff:g> fotky?</item>
<item quantity="other">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> smazat <xliff:g id="COUNT">^2</xliff:g> fotek?</item>
<item quantity="one">Povolit aplikaci <xliff:g id="APP_NAME_0">^1</xliff:g> smazat tuto fotku?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="few">Mazání <xliff:g id="COUNT">^1</xliff:g> fotek…</item>
+ <item quantity="many">Mazání <xliff:g id="COUNT">^1</xliff:g> fotky…</item>
+ <item quantity="other">Mazání <xliff:g id="COUNT">^1</xliff:g> fotek…</item>
+ <item quantity="one">Mazání fotky…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="few">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> smazat <xliff:g id="COUNT">^2</xliff:g> položky?</item>
<item quantity="many">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> smazat <xliff:g id="COUNT">^2</xliff:g> položky?</item>
<item quantity="other">Povolit aplikaci <xliff:g id="APP_NAME_1">^1</xliff:g> smazat <xliff:g id="COUNT">^2</xliff:g> položek?</item>
<item quantity="one">Povolit aplikaci <xliff:g id="APP_NAME_0">^1</xliff:g> smazat tuto položku?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="few">Mazání <xliff:g id="COUNT">^1</xliff:g> položek…</item>
+ <item quantity="many">Mazání <xliff:g id="COUNT">^1</xliff:g> položky…</item>
+ <item quantity="other">Mazání <xliff:g id="COUNT">^1</xliff:g> položek…</item>
+ <item quantity="one">Mazání položky…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"Aplikace <xliff:g id="APP_NAME">%s</xliff:g> nedokáže zpracovat mediální soubory"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Zpracování mediálního obsahu bylo zrušeno"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Při zpracování mediálního obsahu došlo k chybě"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Zpracování mediálního obsahu bylo úspěšně dokončeno"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Zpracování mediálního obsahu bylo zahájeno"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Mediální obsah se zpracovává…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Zrušit"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Počkat"</string>
</resources>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 96ee522..e5bba25 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -47,64 +47,136 @@
<item quantity="one">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at ændre <xliff:g id="COUNT">^2</xliff:g> lydfil?</item>
<item quantity="other">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at ændre <xliff:g id="COUNT">^2</xliff:g> lydfiler?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="one">Ændrer <xliff:g id="COUNT">^1</xliff:g> lydfil…</item>
+ <item quantity="other">Ændrer <xliff:g id="COUNT">^1</xliff:g> lydfiler…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="one">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at ændre <xliff:g id="COUNT">^2</xliff:g> video?</item>
<item quantity="other">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at ændre <xliff:g id="COUNT">^2</xliff:g> videoer?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="one">Ændrer <xliff:g id="COUNT">^1</xliff:g> video…</item>
+ <item quantity="other">Ændrer <xliff:g id="COUNT">^1</xliff:g> videoer…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="one">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at ændre <xliff:g id="COUNT">^2</xliff:g> billede?</item>
<item quantity="other">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at ændre <xliff:g id="COUNT">^2</xliff:g> billeder?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="one">Ændrer <xliff:g id="COUNT">^1</xliff:g> billede…</item>
+ <item quantity="other">Ændrer <xliff:g id="COUNT">^1</xliff:g> billeder…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="one">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at ændre <xliff:g id="COUNT">^2</xliff:g> element?</item>
<item quantity="other">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at ændre <xliff:g id="COUNT">^2</xliff:g> elementer?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="one">Ændrer <xliff:g id="COUNT">^1</xliff:g> element…</item>
+ <item quantity="other">Ændrer <xliff:g id="COUNT">^1</xliff:g> elementer…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="one">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at flytte <xliff:g id="COUNT">^2</xliff:g> lydfil til papirkurven?</item>
<item quantity="other">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at flytte <xliff:g id="COUNT">^2</xliff:g> lydfiler til papirkurven?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="one">Flytter <xliff:g id="COUNT">^1</xliff:g> lydfil til papirkurven…</item>
+ <item quantity="other">Flytter <xliff:g id="COUNT">^1</xliff:g> lydfiler til papirkurven…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="one">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at flytte <xliff:g id="COUNT">^2</xliff:g> video til papirkurven?</item>
<item quantity="other">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at flytte <xliff:g id="COUNT">^2</xliff:g> videoer til papirkurven?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="one">Flytter <xliff:g id="COUNT">^1</xliff:g> video til papirkurven…</item>
+ <item quantity="other">Flytter <xliff:g id="COUNT">^1</xliff:g> videoer til papirkurven…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="one">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at flytte <xliff:g id="COUNT">^2</xliff:g> billede til papirkurven?</item>
<item quantity="other">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at flytte <xliff:g id="COUNT">^2</xliff:g> billeder til papirkurven?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="one">Flytter <xliff:g id="COUNT">^1</xliff:g> billede til papirkurven…</item>
+ <item quantity="other">Flytter <xliff:g id="COUNT">^1</xliff:g> billeder til papirkurven…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="one">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at flytte <xliff:g id="COUNT">^2</xliff:g> element til papirkurven?</item>
<item quantity="other">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at flytte <xliff:g id="COUNT">^2</xliff:g> elementer til papirkurven?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="one">Flytter <xliff:g id="COUNT">^1</xliff:g> element til papirkurven…</item>
+ <item quantity="other">Flytter <xliff:g id="COUNT">^1</xliff:g> elementer til papirkurven…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="one">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at flytte <xliff:g id="COUNT">^2</xliff:g> lydfil ud af papirkurven?</item>
<item quantity="other">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at flytte <xliff:g id="COUNT">^2</xliff:g> lydfiler ud af papirkurven?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="one">Flytter <xliff:g id="COUNT">^1</xliff:g> lydfil ud af papirkurven…</item>
+ <item quantity="other">Flytter <xliff:g id="COUNT">^1</xliff:g> lydfiler ud af papirkurven…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="one">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at flytte <xliff:g id="COUNT">^2</xliff:g> video ud af papirkurven?</item>
<item quantity="other">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at flytte <xliff:g id="COUNT">^2</xliff:g> videoer ud af papirkurven?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="one">Flytter <xliff:g id="COUNT">^1</xliff:g> video ud af papirkurven…</item>
+ <item quantity="other">Flytter <xliff:g id="COUNT">^1</xliff:g> videoer ud af papirkurven…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="one">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at flytte <xliff:g id="COUNT">^2</xliff:g> billede ud af papirkurven?</item>
<item quantity="other">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at flytte <xliff:g id="COUNT">^2</xliff:g> billeder ud af papirkurven?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="one">Flytter <xliff:g id="COUNT">^1</xliff:g> billede ud af papirkurven…</item>
+ <item quantity="other">Flytter <xliff:g id="COUNT">^1</xliff:g> billeder ud af papirkurven…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="one">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at flytte <xliff:g id="COUNT">^2</xliff:g> element ud af papirkurven?</item>
<item quantity="other">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at flytte <xliff:g id="COUNT">^2</xliff:g> elementer ud af papirkurven?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="one">Flytter <xliff:g id="COUNT">^1</xliff:g> element ud af papirkurven…</item>
+ <item quantity="other">Flytter <xliff:g id="COUNT">^1</xliff:g> elementer ud af papirkurven…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="one">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at slette <xliff:g id="COUNT">^2</xliff:g> lydfil?</item>
<item quantity="other">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at slette <xliff:g id="COUNT">^2</xliff:g> lydfiler?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="one">Sletter <xliff:g id="COUNT">^1</xliff:g> lydfil…</item>
+ <item quantity="other">Sletter <xliff:g id="COUNT">^1</xliff:g> lydfiler…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="one">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at slette <xliff:g id="COUNT">^2</xliff:g> video?</item>
<item quantity="other">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at slette <xliff:g id="COUNT">^2</xliff:g> videoer?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="one">Sletter <xliff:g id="COUNT">^1</xliff:g> video…</item>
+ <item quantity="other">Sletter <xliff:g id="COUNT">^1</xliff:g> videoer…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="one">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at slette <xliff:g id="COUNT">^2</xliff:g> billede?</item>
<item quantity="other">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at slette <xliff:g id="COUNT">^2</xliff:g> billeder?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="one">Sletter <xliff:g id="COUNT">^1</xliff:g> billede…</item>
+ <item quantity="other">Sletter <xliff:g id="COUNT">^1</xliff:g> billeder…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="one">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at slette <xliff:g id="COUNT">^2</xliff:g> element?</item>
<item quantity="other">Vil du give <xliff:g id="APP_NAME_1">^1</xliff:g> tilladelse til at slette <xliff:g id="COUNT">^2</xliff:g> elementer?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="one">Sletter <xliff:g id="COUNT">^1</xliff:g> element…</item>
+ <item quantity="other">Sletter <xliff:g id="COUNT">^1</xliff:g> elementer…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> kan ikke behandle mediefiler"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Mediebehandlingen er annulleret"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Mediebehandlingsfejl"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Mediebehandlingen er fuldført"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Mediebehandlingen er startet"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Behandler medier…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Annuller"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Vent"</string>
</resources>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 8b19ff5..6a0001a 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">Darf <xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> Audiodateien ändern?</item>
<item quantity="one">Darf <xliff:g id="APP_NAME_0">^1</xliff:g> diese Audiodatei ändern?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> Audiodateien werden geändert…</item>
+ <item quantity="one">Audiodatei wird geändert…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">Darf <xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> Videos ändern?</item>
<item quantity="one">Darf <xliff:g id="APP_NAME_0">^1</xliff:g> dieses Video ändern?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> Videos werden geändert…</item>
+ <item quantity="one">Video wird geändert…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">Darf <xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> Fotos ändern?</item>
<item quantity="one">Darf <xliff:g id="APP_NAME_0">^1</xliff:g> dieses Foto ändern?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> Fotos werden geändert…</item>
+ <item quantity="one">Foto wird geändert…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">Darf <xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> Elemente ändern?</item>
<item quantity="one">Darf <xliff:g id="APP_NAME_0">^1</xliff:g> dieses Element ändern?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> Elemente werden geändert…</item>
+ <item quantity="one">Element wird geändert…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">Darf <xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> Audiodateien in den Papierkorb verschieben?</item>
<item quantity="one">Darf <xliff:g id="APP_NAME_0">^1</xliff:g> diese Audiodatei in den Papierkorb verschieben?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> Audiodateien werden in den Papierkorb verschoben…</item>
+ <item quantity="one">Audiodatei wird in den Papierkorb verschoben…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">Darf <xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> Videos in den Papierkorb verschieben?</item>
<item quantity="one">Darf <xliff:g id="APP_NAME_0">^1</xliff:g> dieses Video in den Papierkorb verschieben?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> Videos werden in den Papierkorb verschoben…</item>
+ <item quantity="one">Video wird in den Papierkorb verschoben…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">Darf <xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> Fotos in den Papierkorb verschieben?</item>
<item quantity="one">Darf <xliff:g id="APP_NAME_0">^1</xliff:g> dieses Foto in den Papierkorb verschieben?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> Fotos werden in den Papierkorb verschoben…</item>
+ <item quantity="one">Foto wird in den Papierkorb verschoben…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">Darf <xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> Elemente in den Papierkorb verschieben?</item>
<item quantity="one">Darf <xliff:g id="APP_NAME_0">^1</xliff:g> dieses Element in den Papierkorb verschieben?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> Elemente werden in den Papierkorb verschoben…</item>
+ <item quantity="one">Element wird in den Papierkorb verschoben…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">Darf <xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> Audiodateien aus dem Papierkorb verschieben?</item>
<item quantity="one">Darf <xliff:g id="APP_NAME_0">^1</xliff:g> diese Audiodatei aus dem Papierkorb verschieben?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> Audiodateien werden aus dem Papierkorb verschoben…</item>
+ <item quantity="one">Audiodatei wird aus dem Papierkorb verschoben…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">Darf <xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> Videos aus dem Papierkorb verschieben?</item>
<item quantity="one">Darf <xliff:g id="APP_NAME_0">^1</xliff:g> dieses Video aus dem Papierkorb verschieben?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> Videos werden aus dem Papierkorb verschoben…</item>
+ <item quantity="one">Video wird aus dem Papierkorb verschoben…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">Darf <xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> Fotos aus dem Papierkorb verschieben?</item>
<item quantity="one">Darf <xliff:g id="APP_NAME_0">^1</xliff:g> dieses Foto aus dem Papierkorb verschieben?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> Fotos werden aus dem Papierkorb verschoben…</item>
+ <item quantity="one">Foto wird aus dem Papierkorb verschoben…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">Darf <xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> Elemente aus dem Papierkorb wiederherstellen?</item>
<item quantity="one">Darf <xliff:g id="APP_NAME_0">^1</xliff:g> dieses Element aus dem Papierkorb verschieben?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> Elemente werden aus dem Papierkorb verschoben…</item>
+ <item quantity="one">Element wird aus dem Papierkorb verschoben…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">Darf <xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> Audiodateien löschen?</item>
<item quantity="one">Darf <xliff:g id="APP_NAME_0">^1</xliff:g> diese Audiodatei löschen?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> Audiodateien werden gelöscht…</item>
+ <item quantity="one">Audiodatei wird gelöscht…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">Darf <xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> Videos löschen?</item>
<item quantity="one">Darf <xliff:g id="APP_NAME_0">^1</xliff:g> dieses Video löschen?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> Videos werden gelöscht…</item>
+ <item quantity="one">Video wird gelöscht…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">Darf <xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> Fotos löschen?</item>
<item quantity="one">Darf <xliff:g id="APP_NAME_0">^1</xliff:g> dieses Foto löschen?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> Fotos werden gelöscht…</item>
+ <item quantity="one">Foto wird gelöscht…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">Darf <xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> Elemente löschen?</item>
<item quantity="one">Darf <xliff:g id="APP_NAME_0">^1</xliff:g> dieses Element löschen?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> Elemente werden gelöscht…</item>
+ <item quantity="one">Element wird gelöscht…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"Die App „<xliff:g id="APP_NAME">%s</xliff:g>“ kann Mediendateien nicht verarbeiten"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Medienverarbeitung abgebrochen"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Fehler bei Medienverarbeitung"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Medienverarbeitung erfolgreich"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Medienverarbeitung gestartet"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Medien werden verarbeitet…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Abbrechen"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Warten"</string>
</resources>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 7045ca0..e50e8f8 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_1">^1</xliff:g> η τροποποίηση <xliff:g id="COUNT">^2</xliff:g> αρχείων ήχου;</item>
<item quantity="one">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_0">^1</xliff:g> η τροποποίηση αυτού του αρχείου ήχου;</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other">Τροποποίηση <xliff:g id="COUNT">^1</xliff:g> αρχείων ήχου…</item>
+ <item quantity="one">Τροποποίηση αρχείου ήχου…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_1">^1</xliff:g> η τροποποίηση <xliff:g id="COUNT">^2</xliff:g> βίντεο;</item>
<item quantity="one">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_0">^1</xliff:g> η τροποποίηση αυτού του βίντεο;</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other">Τροποποίηση <xliff:g id="COUNT">^1</xliff:g> βίντεο…</item>
+ <item quantity="one">Τροποποίηση βίντεο…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_1">^1</xliff:g> η τροποποίηση <xliff:g id="COUNT">^2</xliff:g> φωτογραφιών;</item>
<item quantity="one">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_0">^1</xliff:g> η τροποποίηση αυτής της φωτογραφίας;</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other">Τροποποίηση <xliff:g id="COUNT">^1</xliff:g> φωτογραφιών…</item>
+ <item quantity="one">Τροποποίηση φωτογραφίας…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_1">^1</xliff:g> η τροποποίηση <xliff:g id="COUNT">^2</xliff:g> στοιχείων;</item>
<item quantity="one">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_0">^1</xliff:g> η τροποποίηση αυτού του στοιχείου;</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other">Τροποποίηση <xliff:g id="COUNT">^1</xliff:g> στοιχείων…</item>
+ <item quantity="one">Τροποποίηση στοιχείου…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_1">^1</xliff:g> η μετακίνηση <xliff:g id="COUNT">^2</xliff:g> αρχείων ήχου στον κάδο;</item>
<item quantity="one">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_0">^1</xliff:g> η μετακίνηση αυτού του αρχείου ήχου στον κάδο;</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other">Μετακίνηση <xliff:g id="COUNT">^1</xliff:g> αρχείων ήχου στον κάδο…</item>
+ <item quantity="one">Μετακίνηση αρχείου ήχου στον κάδο…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_1">^1</xliff:g> η μετακίνηση <xliff:g id="COUNT">^2</xliff:g> βίντεο στον κάδο;</item>
<item quantity="one">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_0">^1</xliff:g> η μετακίνηση αυτού του βίντεο στον κάδο;</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other">Μετακίνηση <xliff:g id="COUNT">^1</xliff:g> βίντεο στον κάδο…</item>
+ <item quantity="one">Μετακίνηση βίντεο στον κάδο…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_1">^1</xliff:g> η μετακίνηση <xliff:g id="COUNT">^2</xliff:g> φωτογραφιών στον κάδο;</item>
<item quantity="one">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_0">^1</xliff:g> η μετακίνηση αυτής της φωτογραφίας στον κάδο;</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other">Μετακίνηση <xliff:g id="COUNT">^1</xliff:g> φωτογραφιών στον κάδο…</item>
+ <item quantity="one">Μετακίνηση φωτογραφίας στον κάδο…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_1">^1</xliff:g> η μετακίνηση <xliff:g id="COUNT">^2</xliff:g> των στοιχείων στον κάδο;</item>
<item quantity="one">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_0">^1</xliff:g> η μετακίνηση αυτού του στοιχείου στον κάδο;</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other">Μετακίνηση <xliff:g id="COUNT">^1</xliff:g> στοιχείων στον κάδο…</item>
+ <item quantity="one">Μετακίνηση στοιχείου στον κάδο…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_1">^1</xliff:g> η μετακίνηση <xliff:g id="COUNT">^2</xliff:g> αρχείων ήχου από τον κάδο;</item>
<item quantity="one">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_0">^1</xliff:g> η μετακίνηση αυτού του αρχείου ήχου από τον κάδο;</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other">Μετακίνηση <xliff:g id="COUNT">^1</xliff:g> αρχείων ήχου από τον κάδο…</item>
+ <item quantity="one">Μετακίνηση αρχείου ήχου από τον κάδο…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_1">^1</xliff:g> η μετακίνηση <xliff:g id="COUNT">^2</xliff:g> βίντεο από τον κάδο;</item>
<item quantity="one">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_0">^1</xliff:g> η μετακίνηση αυτού του βίντεο από τον κάδο;</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other">Μετακίνηση <xliff:g id="COUNT">^1</xliff:g> βίντεο από τον κάδο…</item>
+ <item quantity="one">Μετακίνηση βίντεο από τον κάδο…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_1">^1</xliff:g> η μετακίνηση <xliff:g id="COUNT">^2</xliff:g> φωτογραφιών από τον κάδο;</item>
<item quantity="one">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_0">^1</xliff:g> η μετακίνηση αυτής της φωτογραφίας από τον κάδο;</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other">Μετακίνηση <xliff:g id="COUNT">^1</xliff:g> φωτογραφιών από τον κάδο…</item>
+ <item quantity="one">Μετακίνηση φωτογραφίας από τον κάδο…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_1">^1</xliff:g> η μετακίνηση <xliff:g id="COUNT">^2</xliff:g> στοιχείων από τον κάδο;</item>
<item quantity="one">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_0">^1</xliff:g> η μετακίνηση αυτού του στοιχείου από τον κάδο;</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other">Μετακίνηση <xliff:g id="COUNT">^1</xliff:g> στοιχείων από τον κάδο…</item>
+ <item quantity="one">Μετακίνηση στοιχείου από τον κάδο…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_1">^1</xliff:g> η διαγραφή <xliff:g id="COUNT">^2</xliff:g> αρχείων ήχου;</item>
<item quantity="one">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_0">^1</xliff:g> η διαγραφή αυτού του αρχείου ήχου;</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other">Διαγραφή <xliff:g id="COUNT">^1</xliff:g> αρχείων ήχου…</item>
+ <item quantity="one">Διαγραφή αρχείου ήχου…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_1">^1</xliff:g> η διαγραφή <xliff:g id="COUNT">^2</xliff:g> βίντεο;</item>
<item quantity="one">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_0">^1</xliff:g> η διαγραφή αυτού του βίντεο;</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other">Διαγραφή <xliff:g id="COUNT">^1</xliff:g> βίντεο…</item>
+ <item quantity="one">Διαγραφή βίντεο…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_1">^1</xliff:g> η διαγραφή <xliff:g id="COUNT">^2</xliff:g> φωτογραφιών;</item>
<item quantity="one">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_0">^1</xliff:g> η διαγραφή αυτής της φωτογραφίας:</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other">Διαγραφή <xliff:g id="COUNT">^1</xliff:g> φωτογραφιών…</item>
+ <item quantity="one">Διαγραφή φωτογραφίας…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_1">^1</xliff:g> η διαγραφή <xliff:g id="COUNT">^2</xliff:g> στοιχείων;</item>
<item quantity="one">Να επιτραπεί στην εφαρμογή <xliff:g id="APP_NAME_0">^1</xliff:g> η διαγραφή αυτού του στοιχείου;</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other">Διαγραφή <xliff:g id="COUNT">^1</xliff:g> στοιχείων…</item>
+ <item quantity="one">Διαγραφή στοιχείου…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"Η εφαρμογή <xliff:g id="APP_NAME">%s</xliff:g> δεν έχει δυνατότητα επεξεργασία αρχείων μέσων"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Η επεξεργασία μέσων ακυρώθηκε"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Σφάλμα επεξεργασίας μέσων"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Η επεξεργασία μέσων ολοκληρώθηκε επιτυχώς"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Η επεξεργασία μέσων ξεκίνησε"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Επεξεργασία μέσων…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Ακύρωση"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Αναμονή"</string>
</resources>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 1205a7e..2f1bda0 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to modify <xliff:g id="COUNT">^2</xliff:g> audio files?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to modify this audio file?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other">Modifying <xliff:g id="COUNT">^1</xliff:g> audio files…</item>
+ <item quantity="one">Modifying audio file…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to modify <xliff:g id="COUNT">^2</xliff:g> videos?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to modify this video?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other">Modifying <xliff:g id="COUNT">^1</xliff:g> videos…</item>
+ <item quantity="one">Modifying video…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to modify <xliff:g id="COUNT">^2</xliff:g> photos?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to modify this photo?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other">Modifying <xliff:g id="COUNT">^1</xliff:g> photos…</item>
+ <item quantity="one">Modifying photo…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to modify <xliff:g id="COUNT">^2</xliff:g> items?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to modify this item?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other">Modifying <xliff:g id="COUNT">^1</xliff:g> items…</item>
+ <item quantity="one">Modifying item…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> audio files to bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this audio file to bin?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> audio files to bin…</item>
+ <item quantity="one">Moving audio file to bin…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> videos to bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this video to bin?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> videos to bin…</item>
+ <item quantity="one">Moving video to bin…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> photos to bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this photo to bin?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> photos to bin…</item>
+ <item quantity="one">Moving photo to bin…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> items to bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this item to bin?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> items to bin…</item>
+ <item quantity="one">Moving item to bin…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> audio files out of bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this audio file out of bin?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> audio files out of bin…</item>
+ <item quantity="one">Moving audio file out of bin…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> videos out of bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this video out of bin?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> videos out of bin…</item>
+ <item quantity="one">Moving video out of bin…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> photos out of bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this photo out of bin?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> photos out of bin…</item>
+ <item quantity="one">Moving photo out of bin…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> items out of bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this item out of bin?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> items out of bin…</item>
+ <item quantity="one">Moving item out of bin…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to delete <xliff:g id="COUNT">^2</xliff:g> audio files?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to delete this audio file?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other">Deleting <xliff:g id="COUNT">^1</xliff:g> audio files…</item>
+ <item quantity="one">Deleting audio file…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to delete <xliff:g id="COUNT">^2</xliff:g> videos?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to delete this video?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other">Deleting <xliff:g id="COUNT">^1</xliff:g> videos…</item>
+ <item quantity="one">Deleting video…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to delete <xliff:g id="COUNT">^2</xliff:g> photos?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to delete this photo?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other">Deleting <xliff:g id="COUNT">^1</xliff:g> photos…</item>
+ <item quantity="one">Deleting photo…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to delete <xliff:g id="COUNT">^2</xliff:g> items?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to delete this item?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other">Deleting <xliff:g id="COUNT">^1</xliff:g> items…</item>
+ <item quantity="one">Deleting item…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> can\'t process media files"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Media processing cancelled"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Media processing error"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Media processing success"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Media processing started"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Processing media…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Cancel"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Wait"</string>
</resources>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index 1205a7e..2f1bda0 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to modify <xliff:g id="COUNT">^2</xliff:g> audio files?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to modify this audio file?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other">Modifying <xliff:g id="COUNT">^1</xliff:g> audio files…</item>
+ <item quantity="one">Modifying audio file…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to modify <xliff:g id="COUNT">^2</xliff:g> videos?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to modify this video?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other">Modifying <xliff:g id="COUNT">^1</xliff:g> videos…</item>
+ <item quantity="one">Modifying video…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to modify <xliff:g id="COUNT">^2</xliff:g> photos?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to modify this photo?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other">Modifying <xliff:g id="COUNT">^1</xliff:g> photos…</item>
+ <item quantity="one">Modifying photo…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to modify <xliff:g id="COUNT">^2</xliff:g> items?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to modify this item?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other">Modifying <xliff:g id="COUNT">^1</xliff:g> items…</item>
+ <item quantity="one">Modifying item…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> audio files to bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this audio file to bin?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> audio files to bin…</item>
+ <item quantity="one">Moving audio file to bin…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> videos to bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this video to bin?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> videos to bin…</item>
+ <item quantity="one">Moving video to bin…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> photos to bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this photo to bin?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> photos to bin…</item>
+ <item quantity="one">Moving photo to bin…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> items to bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this item to bin?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> items to bin…</item>
+ <item quantity="one">Moving item to bin…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> audio files out of bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this audio file out of bin?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> audio files out of bin…</item>
+ <item quantity="one">Moving audio file out of bin…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> videos out of bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this video out of bin?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> videos out of bin…</item>
+ <item quantity="one">Moving video out of bin…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> photos out of bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this photo out of bin?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> photos out of bin…</item>
+ <item quantity="one">Moving photo out of bin…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> items out of bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this item out of bin?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> items out of bin…</item>
+ <item quantity="one">Moving item out of bin…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to delete <xliff:g id="COUNT">^2</xliff:g> audio files?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to delete this audio file?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other">Deleting <xliff:g id="COUNT">^1</xliff:g> audio files…</item>
+ <item quantity="one">Deleting audio file…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to delete <xliff:g id="COUNT">^2</xliff:g> videos?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to delete this video?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other">Deleting <xliff:g id="COUNT">^1</xliff:g> videos…</item>
+ <item quantity="one">Deleting video…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to delete <xliff:g id="COUNT">^2</xliff:g> photos?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to delete this photo?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other">Deleting <xliff:g id="COUNT">^1</xliff:g> photos…</item>
+ <item quantity="one">Deleting photo…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to delete <xliff:g id="COUNT">^2</xliff:g> items?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to delete this item?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other">Deleting <xliff:g id="COUNT">^1</xliff:g> items…</item>
+ <item quantity="one">Deleting item…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> can\'t process media files"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Media processing cancelled"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Media processing error"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Media processing success"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Media processing started"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Processing media…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Cancel"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Wait"</string>
</resources>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 1205a7e..2f1bda0 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to modify <xliff:g id="COUNT">^2</xliff:g> audio files?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to modify this audio file?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other">Modifying <xliff:g id="COUNT">^1</xliff:g> audio files…</item>
+ <item quantity="one">Modifying audio file…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to modify <xliff:g id="COUNT">^2</xliff:g> videos?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to modify this video?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other">Modifying <xliff:g id="COUNT">^1</xliff:g> videos…</item>
+ <item quantity="one">Modifying video…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to modify <xliff:g id="COUNT">^2</xliff:g> photos?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to modify this photo?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other">Modifying <xliff:g id="COUNT">^1</xliff:g> photos…</item>
+ <item quantity="one">Modifying photo…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to modify <xliff:g id="COUNT">^2</xliff:g> items?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to modify this item?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other">Modifying <xliff:g id="COUNT">^1</xliff:g> items…</item>
+ <item quantity="one">Modifying item…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> audio files to bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this audio file to bin?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> audio files to bin…</item>
+ <item quantity="one">Moving audio file to bin…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> videos to bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this video to bin?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> videos to bin…</item>
+ <item quantity="one">Moving video to bin…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> photos to bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this photo to bin?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> photos to bin…</item>
+ <item quantity="one">Moving photo to bin…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> items to bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this item to bin?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> items to bin…</item>
+ <item quantity="one">Moving item to bin…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> audio files out of bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this audio file out of bin?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> audio files out of bin…</item>
+ <item quantity="one">Moving audio file out of bin…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> videos out of bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this video out of bin?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> videos out of bin…</item>
+ <item quantity="one">Moving video out of bin…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> photos out of bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this photo out of bin?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> photos out of bin…</item>
+ <item quantity="one">Moving photo out of bin…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> items out of bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this item out of bin?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> items out of bin…</item>
+ <item quantity="one">Moving item out of bin…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to delete <xliff:g id="COUNT">^2</xliff:g> audio files?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to delete this audio file?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other">Deleting <xliff:g id="COUNT">^1</xliff:g> audio files…</item>
+ <item quantity="one">Deleting audio file…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to delete <xliff:g id="COUNT">^2</xliff:g> videos?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to delete this video?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other">Deleting <xliff:g id="COUNT">^1</xliff:g> videos…</item>
+ <item quantity="one">Deleting video…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to delete <xliff:g id="COUNT">^2</xliff:g> photos?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to delete this photo?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other">Deleting <xliff:g id="COUNT">^1</xliff:g> photos…</item>
+ <item quantity="one">Deleting photo…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to delete <xliff:g id="COUNT">^2</xliff:g> items?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to delete this item?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other">Deleting <xliff:g id="COUNT">^1</xliff:g> items…</item>
+ <item quantity="one">Deleting item…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> can\'t process media files"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Media processing cancelled"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Media processing error"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Media processing success"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Media processing started"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Processing media…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Cancel"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Wait"</string>
</resources>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 1205a7e..2f1bda0 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to modify <xliff:g id="COUNT">^2</xliff:g> audio files?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to modify this audio file?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other">Modifying <xliff:g id="COUNT">^1</xliff:g> audio files…</item>
+ <item quantity="one">Modifying audio file…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to modify <xliff:g id="COUNT">^2</xliff:g> videos?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to modify this video?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other">Modifying <xliff:g id="COUNT">^1</xliff:g> videos…</item>
+ <item quantity="one">Modifying video…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to modify <xliff:g id="COUNT">^2</xliff:g> photos?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to modify this photo?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other">Modifying <xliff:g id="COUNT">^1</xliff:g> photos…</item>
+ <item quantity="one">Modifying photo…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to modify <xliff:g id="COUNT">^2</xliff:g> items?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to modify this item?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other">Modifying <xliff:g id="COUNT">^1</xliff:g> items…</item>
+ <item quantity="one">Modifying item…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> audio files to bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this audio file to bin?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> audio files to bin…</item>
+ <item quantity="one">Moving audio file to bin…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> videos to bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this video to bin?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> videos to bin…</item>
+ <item quantity="one">Moving video to bin…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> photos to bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this photo to bin?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> photos to bin…</item>
+ <item quantity="one">Moving photo to bin…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> items to bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this item to bin?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> items to bin…</item>
+ <item quantity="one">Moving item to bin…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> audio files out of bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this audio file out of bin?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> audio files out of bin…</item>
+ <item quantity="one">Moving audio file out of bin…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> videos out of bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this video out of bin?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> videos out of bin…</item>
+ <item quantity="one">Moving video out of bin…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> photos out of bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this photo out of bin?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> photos out of bin…</item>
+ <item quantity="one">Moving photo out of bin…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> items out of bin?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this item out of bin?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> items out of bin…</item>
+ <item quantity="one">Moving item out of bin…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to delete <xliff:g id="COUNT">^2</xliff:g> audio files?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to delete this audio file?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other">Deleting <xliff:g id="COUNT">^1</xliff:g> audio files…</item>
+ <item quantity="one">Deleting audio file…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to delete <xliff:g id="COUNT">^2</xliff:g> videos?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to delete this video?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other">Deleting <xliff:g id="COUNT">^1</xliff:g> videos…</item>
+ <item quantity="one">Deleting video…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to delete <xliff:g id="COUNT">^2</xliff:g> photos?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to delete this photo?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other">Deleting <xliff:g id="COUNT">^1</xliff:g> photos…</item>
+ <item quantity="one">Deleting photo…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to delete <xliff:g id="COUNT">^2</xliff:g> items?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to delete this item?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other">Deleting <xliff:g id="COUNT">^1</xliff:g> items…</item>
+ <item quantity="one">Deleting item…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> can\'t process media files"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Media processing cancelled"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Media processing error"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Media processing success"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Media processing started"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Processing media…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Cancel"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Wait"</string>
</resources>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index 18ba860..707a0f5 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to modify <xliff:g id="COUNT">^2</xliff:g> audio files?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to modify this audio file?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other">Modifying <xliff:g id="COUNT">^1</xliff:g> audio files…</item>
+ <item quantity="one">Modifying audio file…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to modify <xliff:g id="COUNT">^2</xliff:g> videos?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to modify this video?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other">Modifying <xliff:g id="COUNT">^1</xliff:g> videos…</item>
+ <item quantity="one">Modifying video…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to modify <xliff:g id="COUNT">^2</xliff:g> photos?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to modify this photo?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other">Modifying <xliff:g id="COUNT">^1</xliff:g> photos…</item>
+ <item quantity="one">Modifying photo…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to modify <xliff:g id="COUNT">^2</xliff:g> items?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to modify this item?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other">Modifying <xliff:g id="COUNT">^1</xliff:g> items…</item>
+ <item quantity="one">Modifying item…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> audio files to trash?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this audio file to trash?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> audio files to trash…</item>
+ <item quantity="one">Moving audio file to trash…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> videos to trash?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this video to trash?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> videos to trash…</item>
+ <item quantity="one">Moving video to trash…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> photos to trash?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this photo to trash?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> photos to trash…</item>
+ <item quantity="one">Moving photo to trash…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> items to trash?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this item to trash?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> items to trash…</item>
+ <item quantity="one">Moving item to trash…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> audio files out of trash?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this audio file out of trash?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> audio files out of trash…</item>
+ <item quantity="one">Moving audio file out of trash…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> videos out of trash?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this video out of trash?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> videos out of trash…</item>
+ <item quantity="one">Moving video out of trash…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> photos out of trash?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this photo out of trash?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> photos out of trash…</item>
+ <item quantity="one">Moving photo out of trash…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> items out of trash?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to move this item out of trash?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other">Moving <xliff:g id="COUNT">^1</xliff:g> items out of trash…</item>
+ <item quantity="one">Moving item out of trash…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to delete <xliff:g id="COUNT">^2</xliff:g> audio files?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to delete this audio file?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other">Deleting <xliff:g id="COUNT">^1</xliff:g> audio files…</item>
+ <item quantity="one">Deleting audio file…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to delete <xliff:g id="COUNT">^2</xliff:g> videos?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to delete this video?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other">Deleting <xliff:g id="COUNT">^1</xliff:g> videos…</item>
+ <item quantity="one">Deleting video…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to delete <xliff:g id="COUNT">^2</xliff:g> photos?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to delete this photo?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other">Deleting <xliff:g id="COUNT">^1</xliff:g> photos…</item>
+ <item quantity="one">Deleting photo…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to delete <xliff:g id="COUNT">^2</xliff:g> items?</item>
<item quantity="one">Allow <xliff:g id="APP_NAME_0">^1</xliff:g> to delete this item?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other">Deleting <xliff:g id="COUNT">^1</xliff:g> items…</item>
+ <item quantity="one">Deleting item…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> can\'t process media files"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Media processing cancelled"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Media processing error"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Media processing success"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Media processing started"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Processing media…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Cancel"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Wait"</string>
</resources>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index e2ffe99..016c843 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">¿Deseas permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> archivos de audio?</item>
<item quantity="one">¿Deseas permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> modifique este archivo de audio?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other">Modificando <xliff:g id="COUNT">^1</xliff:g> archivos de audio…</item>
+ <item quantity="one">Modificando el archivo de audio…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">¿Deseas permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> videos?</item>
<item quantity="one">¿Deseas permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> modifique este video?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other">Modificando <xliff:g id="COUNT">^1</xliff:g> videos…</item>
+ <item quantity="one">Modificando el video…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">¿Deseas permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> fotos?</item>
<item quantity="one">¿Deseas permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> modifique esta foto?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other">Modificando <xliff:g id="COUNT">^1</xliff:g> fotos…</item>
+ <item quantity="one">Modificando la foto…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">¿Deseas permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> elementos?</item>
<item quantity="one">¿Deseas permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> modifique este elemento?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other">Modificando <xliff:g id="COUNT">^1</xliff:g> elementos…</item>
+ <item quantity="one">Modificando el elemento…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">¿Deseas permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> mueva <xliff:g id="COUNT">^2</xliff:g> archivos de audio a la papelera?</item>
<item quantity="one">¿Deseas permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> mueva este archivo de audio a la papelera?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other">Moviendo <xliff:g id="COUNT">^1</xliff:g> archivos de audio a la papelera…</item>
+ <item quantity="one">Moviendo el archivo de audio a la papelera…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">¿Deseas permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> mueva <xliff:g id="COUNT">^2</xliff:g> videos a la papelera?</item>
<item quantity="one">¿Deseas permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> mueva este video a la papelera?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other">Moviendo <xliff:g id="COUNT">^1</xliff:g> videos a la papelera…</item>
+ <item quantity="one">Moviendo el video a la papelera…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">¿Deseas permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> mueva <xliff:g id="COUNT">^2</xliff:g> fotos a la papelera?</item>
<item quantity="one">¿Deseas permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> mueva esta foto a la papelera?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other">Moviendo <xliff:g id="COUNT">^1</xliff:g> fotos a la papelera…</item>
+ <item quantity="one">Moviendo la foto a la papelera…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">¿Deseas permitir <xliff:g id="APP_NAME_1">^1</xliff:g> mueva <xliff:g id="COUNT">^2</xliff:g> elementos a la papelera?</item>
<item quantity="one">¿Deseas permitir <xliff:g id="APP_NAME_0">^1</xliff:g> mueva este elemento a la papelera?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other">Moviendo <xliff:g id="COUNT">^1</xliff:g> elementos a la papelera…</item>
+ <item quantity="one">Moviendo el elemento a la papelera…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">¿Deseas permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> quite <xliff:g id="COUNT">^2</xliff:g> archivos de audio de la papelera?</item>
<item quantity="one">¿Deseas permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> quite este archivo de audio de la papelera?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other">Quitando <xliff:g id="COUNT">^1</xliff:g> archivos de audio de la papelera…</item>
+ <item quantity="one">Quitando el archivo de audio de la papelera…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">¿Deseas permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> quite <xliff:g id="COUNT">^2</xliff:g> videos de la papelera?</item>
<item quantity="one">¿Deseas permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> quite este video de la papelera?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other">Quitando <xliff:g id="COUNT">^1</xliff:g> videos de la papelera…</item>
+ <item quantity="one">Quitando el video de la papelera…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">¿Deseas permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> quite <xliff:g id="COUNT">^2</xliff:g> fotos de la papelera?</item>
<item quantity="one">¿Deseas permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> quite esta foto de la papelera?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other">Quitando <xliff:g id="COUNT">^1</xliff:g> fotos de la papelera…</item>
+ <item quantity="one">Quitando la foto de la papelera…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">¿Deseas permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> quite <xliff:g id="COUNT">^2</xliff:g> elementos de la papelera?</item>
<item quantity="one">¿Deseas permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> quite este elemento de la papelera?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other">Quitando <xliff:g id="COUNT">^1</xliff:g> elementos de la papelera…</item>
+ <item quantity="one">Quitando el elemento de la papelera…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">¿Deseas permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> borre <xliff:g id="COUNT">^2</xliff:g> archivos de audio?</item>
<item quantity="one">¿Deseas permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> borre este archivo de audio?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other">Borrando <xliff:g id="COUNT">^1</xliff:g> archivos de audio…</item>
+ <item quantity="one">Borrando el archivo de audio…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">¿Deseas permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> borre <xliff:g id="COUNT">^2</xliff:g> videos?</item>
<item quantity="one">¿Deseas permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> borre este video?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other">Borrando <xliff:g id="COUNT">^1</xliff:g> videos…</item>
+ <item quantity="one">Borrando el video…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">¿Deseas permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> borre <xliff:g id="COUNT">^2</xliff:g> fotos?</item>
<item quantity="one">¿Deseas permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> borre esta foto?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other">Borrando <xliff:g id="COUNT">^1</xliff:g> fotos…</item>
+ <item quantity="one">Borrando la foto…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">¿Deseas permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> borre <xliff:g id="COUNT">^2</xliff:g> elementos?</item>
<item quantity="one">¿Deseas permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> borre este elemento?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other">Borrando <xliff:g id="COUNT">^1</xliff:g> elementos…</item>
+ <item quantity="one">Borrando el elemento…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> no puede procesar archivos multimedia"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Se canceló el procesamiento de contenido multimedia"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Error al procesar el contenido multimedia"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Se procesó correctamente el contenido multimedia"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Comenzó el procesamiento de contenido multimedia"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Procesando contenido multimedia…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Cancelar"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Esperar"</string>
</resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 7d0ee18..89b404f 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">¿Permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> archivos de audio?</item>
<item quantity="one">¿Permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> modifique este archivo de audio?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other">Modificando <xliff:g id="COUNT">^1</xliff:g> archivos de audio…</item>
+ <item quantity="one">Modificando archivo de audio…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">¿Permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> vídeos?</item>
<item quantity="one">¿Permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> modifique este vídeo?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other">Modificando <xliff:g id="COUNT">^1</xliff:g> vídeos…</item>
+ <item quantity="one">Modificando vídeo…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">¿Permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> fotos?</item>
<item quantity="one">¿Permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> modifique esta foto?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other">Modificando <xliff:g id="COUNT">^1</xliff:g> fotos…</item>
+ <item quantity="one">Modificando foto…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">¿Permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> elementos?</item>
<item quantity="one">¿Permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> modifique este elemento?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other">Modificando <xliff:g id="COUNT">^1</xliff:g> elementos…</item>
+ <item quantity="one">Modificando elemento…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">¿Permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> mueva <xliff:g id="COUNT">^2</xliff:g> archivos de audio a la papelera?</item>
<item quantity="one">¿Permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> mueva este archivo de audio a la papelera?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other">Moviendo <xliff:g id="COUNT">^1</xliff:g> archivos de audio a la papelera…</item>
+ <item quantity="one">Moviendo archivo de audio a la papelera…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">¿Permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> mueva <xliff:g id="COUNT">^2</xliff:g> vídeos a la papelera?</item>
<item quantity="one">¿Permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> mueva este vídeo a la papelera?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other">Moviendo <xliff:g id="COUNT">^1</xliff:g> vídeos a la papelera…</item>
+ <item quantity="one">Moviendo vídeo a la papelera…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">¿Permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> mueva <xliff:g id="COUNT">^2</xliff:g> fotos a la papelera?</item>
<item quantity="one">¿Permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> mueva esta foto a la papelera?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other">Moviendo <xliff:g id="COUNT">^1</xliff:g> fotos a la papelera…</item>
+ <item quantity="one">Moviendo foto a la papelera…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">¿Permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> mueva <xliff:g id="COUNT">^2</xliff:g> elementos a la papelera?</item>
<item quantity="one">¿Permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> mueva este elemento a la papelera?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other">Moviendo <xliff:g id="COUNT">^1</xliff:g> elementos a la papelera…</item>
+ <item quantity="one">Moviendo elemento a la papelera…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">¿Permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> quite <xliff:g id="COUNT">^2</xliff:g> archivos de audio de la papelera?</item>
<item quantity="one">¿Permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> quite este archivo de audio de la papelera?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other">Quitando <xliff:g id="COUNT">^1</xliff:g> archivos de audio de la papelera…</item>
+ <item quantity="one">Quitando archivo de audio de la papelera…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">¿Permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> quite <xliff:g id="COUNT">^2</xliff:g> vídeos de la papelera?</item>
<item quantity="one">¿Permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> quite este vídeo de la papelera?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other">Quitando <xliff:g id="COUNT">^1</xliff:g> vídeos de la papelera…</item>
+ <item quantity="one">Quitando vídeo de la papelera…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">¿Permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> quite <xliff:g id="COUNT">^2</xliff:g> fotos de la papelera?</item>
<item quantity="one">¿Permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> quite esta foto de la papelera?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other">Quitando <xliff:g id="COUNT">^1</xliff:g> fotos de la papelera…</item>
+ <item quantity="one">Quitando foto de la papelera…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">¿Permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> quite <xliff:g id="COUNT">^2</xliff:g> elementos de la papelera?</item>
<item quantity="one">¿Permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> quite este elemento de la papelera?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other">Quitando <xliff:g id="COUNT">^1</xliff:g> elementos de la papelera…</item>
+ <item quantity="one">Quitando elemento de la papelera…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">¿Permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> elimine <xliff:g id="COUNT">^2</xliff:g> archivos de audio?</item>
<item quantity="one">¿Permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> elimine este archivo de audio?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other">Eliminando <xliff:g id="COUNT">^1</xliff:g> archivos de audio…</item>
+ <item quantity="one">Eliminando archivo de audio…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">¿Permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> elimine <xliff:g id="COUNT">^2</xliff:g> vídeos?</item>
<item quantity="one">¿Permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> elimine este vídeo?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other">Eliminando <xliff:g id="COUNT">^1</xliff:g> vídeos…</item>
+ <item quantity="one">Eliminando vídeo…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">¿Permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> elimine <xliff:g id="COUNT">^2</xliff:g> fotos?</item>
<item quantity="one">¿Permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> elimine esta foto?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other">Eliminando <xliff:g id="COUNT">^1</xliff:g> fotos…</item>
+ <item quantity="one">Eliminando foto…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">¿Permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> elimine <xliff:g id="COUNT">^2</xliff:g> elementos?</item>
<item quantity="one">¿Permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> elimine este elemento?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other">Eliminando <xliff:g id="COUNT">^1</xliff:g> elementos…</item>
+ <item quantity="one">Eliminando elemento…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> no puede procesar archivos multimedia"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Procesamiento de elementos multimedia cancelado"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"No se han podido procesar elementos multimedia"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Elementos multimedia procesados"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Procesamiento de elementos multimedia iniciado"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Procesando elementos multimedia…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Cancelar"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Espera"</string>
</resources>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 1dbfc5c..27a526a 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">Kas lubada rakendusel <xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> helifaili muuta?</item>
<item quantity="one">Kas lubada rakendusel <xliff:g id="APP_NAME_0">^1</xliff:g> seda helifaili muuta?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> helifaili töötlemine …</item>
+ <item quantity="one">Helifaili töötlemine …</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">Kas lubada rakendusel <xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> videot muuta?</item>
<item quantity="one">Kas lubada rakendusel <xliff:g id="APP_NAME_0">^1</xliff:g> seda videot muuta?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> video töötlemine …</item>
+ <item quantity="one">Video töötlemine …</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">Kas lubada rakendusel <xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> fotot muuta?</item>
<item quantity="one">Kas lubada rakendusel <xliff:g id="APP_NAME_0">^1</xliff:g> seda fotot muuta?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> foto töötlemine …</item>
+ <item quantity="one">Foto töötlemine …</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">Kas lubada rakendusel <xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> üksust muuta?</item>
<item quantity="one">Kas lubada rakendusel <xliff:g id="APP_NAME_0">^1</xliff:g> seda üksust muuta?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> üksuse töötlemine …</item>
+ <item quantity="one">Üksuse töötlemine …</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">Kas lubada rakendusel <xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> helifaili prügikasti teisaldada?</item>
<item quantity="one">Kas lubada rakendusel <xliff:g id="APP_NAME_0">^1</xliff:g> see helifail prügikasti teisaldada?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> helifaili teisaldamine prügikasti …</item>
+ <item quantity="one">Helifaili teisaldamine prügikasti …</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">Kas lubada rakendusel <xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> videot prügikasti teisaldada?</item>
<item quantity="one">Kas lubada rakendusel <xliff:g id="APP_NAME_0">^1</xliff:g> see video prügikasti teisaldada?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> video teisaldamine prügikasti …</item>
+ <item quantity="one">Video teisaldamine prügikasti …</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">Kas lubada rakendusel <xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> fotot prügikasti teisaldada?</item>
<item quantity="one">Kas lubada rakendusel <xliff:g id="APP_NAME_0">^1</xliff:g> see foto prügikasti teisaldada?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> foto teisaldamine prügikasti …</item>
+ <item quantity="one">Foto teisaldamine prügikasti …</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">Kas lubada rakendusel <xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> üksust prügikasti teisaldada?</item>
<item quantity="one">Kas lubada rakendusel <xliff:g id="APP_NAME_0">^1</xliff:g> see üksus prügikasti teisaldada?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> üksuse teisaldamine prügikasti …</item>
+ <item quantity="one">Üksuse teisaldamine prügikasti …</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">Kas lubada rakendusel <xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> helifaili prügikastist taastada?</item>
<item quantity="one">Kas lubada rakendusel <xliff:g id="APP_NAME_0">^1</xliff:g> selle helifaili prügikastist taastada?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> helifaili taastamine prügikastist …</item>
+ <item quantity="one">Helifaili taastamine prügikastist …</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">Kas lubada rakendusel <xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> videot prügikastist taastada?</item>
<item quantity="one">Kas lubada rakendusel <xliff:g id="APP_NAME_0">^1</xliff:g> selle video prügikastist taastada?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> video taastamine prügikastist …</item>
+ <item quantity="one">Video taastamine prügikastist …</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">Kas lubada rakendusel <xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> fotot prügikastist taastada?</item>
<item quantity="one">Kas lubada rakendusel <xliff:g id="APP_NAME_0">^1</xliff:g> selle foto prügikastist taastada?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> foto taastamine prügikastist …</item>
+ <item quantity="one">Foto taastamine prügikastist …</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">Kas lubada rakendusel <xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> üksust prügikastist taastada?</item>
<item quantity="one">Kas lubada rakendusel <xliff:g id="APP_NAME_0">^1</xliff:g> selle üksuse prügikastist taastada?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> üksuse taastamine prügikastist …</item>
+ <item quantity="one">Üksuse taastamine prügikastist …</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">Kas soovite lubada rakendusel <xliff:g id="APP_NAME_1">^1</xliff:g> kustutada <xliff:g id="COUNT">^2</xliff:g> helifaili?</item>
<item quantity="one">Kas soovite lubada rakendusel <xliff:g id="APP_NAME_0">^1</xliff:g> selle helifaili kustutada?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> helifaili kustutamine …</item>
+ <item quantity="one">Helifaili kustutamine …</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">Kas soovite lubada rakendusel <xliff:g id="APP_NAME_1">^1</xliff:g> kustutada <xliff:g id="COUNT">^2</xliff:g> videot?</item>
<item quantity="one">Kas soovite lubada rakendusel <xliff:g id="APP_NAME_0">^1</xliff:g> selle video kustutada?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> video kustutamine …</item>
+ <item quantity="one">Video kustutamine …</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">Kas soovite lubada rakendusel <xliff:g id="APP_NAME_1">^1</xliff:g> kustutada <xliff:g id="COUNT">^2</xliff:g> fotot?</item>
<item quantity="one">Kas soovite lubada rakendusel <xliff:g id="APP_NAME_0">^1</xliff:g> selle foto kustutada?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> foto kustutamine …</item>
+ <item quantity="one">Foto kustutamine …</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">Kas soovite lubada rakendusel <xliff:g id="APP_NAME_1">^1</xliff:g> kustutada <xliff:g id="COUNT">^2</xliff:g> üksust?</item>
<item quantity="one">Kas soovite lubada rakendusel <xliff:g id="APP_NAME_0">^1</xliff:g> selle üksuse kustutada?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> üksuse kustutamine …</item>
+ <item quantity="one">Üksuse kustutamine …</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> ei saa meediafaile töödelda"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Meedia töötlemine tühistati"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Viga meedia töötlemisel"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Meedia töötlemine õnnestus"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Alustati meedia töötlemist"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Meedia töötlemine …"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Tühista"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Oota"</string>
</resources>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index a4b655a..707e083 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> audio-fitxategiri aldaketak egiteko baimena eman nahi diozu <xliff:g id="APP_NAME_1">^1</xliff:g> aplikazioari?</item>
<item quantity="one">Audio-fitxategi honi aldaketak egiteko baimena eman nahi diozu <xliff:g id="APP_NAME_0">^1</xliff:g> aplikazioari?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> audio-fitxategi aldatzen…</item>
+ <item quantity="one">Audio-fitxategia aldatzen…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> bideori aldaketak egiteko baimena eman nahi diozu <xliff:g id="APP_NAME_1">^1</xliff:g> aplikazioari?</item>
<item quantity="one">Bideo honi aldaketak egiteko baimena eman nahi diozu <xliff:g id="APP_NAME_0">^1</xliff:g> aplikazioari?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> bideo aldatzen…</item>
+ <item quantity="one">Bideoa aldatzen…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> argazkiri aldaketak egiteko baimena eman nahi diozu <xliff:g id="APP_NAME_1">^1</xliff:g> aplikazioari?</item>
<item quantity="one">Argazki honi aldaketak egiteko baimena eman nahi diozu <xliff:g id="APP_NAME_0">^1</xliff:g> aplikazioari?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> argazki aldatzen…</item>
+ <item quantity="one">Argazkia aldatzen…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> elementuri aldaketak egiteko baimena eman nahi diozu <xliff:g id="APP_NAME_1">^1</xliff:g> aplikazioari?</item>
<item quantity="one">Elementu honi aldaketak egiteko baimena eman nahi diozu <xliff:g id="APP_NAME_0">^1</xliff:g> aplikazioari?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> elementu aldatzen…</item>
+ <item quantity="one">Elementua aldatzen…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> audio-fitxategi zaborrontzira eramateko baimena eman nahi diozu <xliff:g id="APP_NAME_1">^1</xliff:g> aplikazioari?</item>
<item quantity="one">Audio-fitxategi hau zaborrontzira eramateko baimena eman nahi diozu <xliff:g id="APP_NAME_0">^1</xliff:g> aplikazioari?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> audio-fitxategi zaborrontzira eramaten…</item>
+ <item quantity="one">Audio-fitxategia zaborrontzira eramaten…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> bideo zaborrontzira eramateko baimena eman nahi diozu <xliff:g id="APP_NAME_1">^1</xliff:g> aplikazioari?</item>
<item quantity="one">Bideo hau zaborrontzira eramateko baimena eman nahi diozu <xliff:g id="APP_NAME_0">^1</xliff:g> aplikazioari?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> bideo zaborrontzira eramaten…</item>
+ <item quantity="one">Bideoa zaborrontzira eramaten…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> argazki zaborrontzira eramateko baimena eman nahi diozu <xliff:g id="APP_NAME_1">^1</xliff:g> aplikazioari?</item>
<item quantity="one">Argazki hau zaborrontzira eramateko baimena eman nahi diozu <xliff:g id="APP_NAME_0">^1</xliff:g> aplikazioari?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> argazki zaborrontzira eramaten…</item>
+ <item quantity="one">Argazkia zaborrontzira eramaten…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> elementu zaborrontzira eramateko baimena eman nahi diozu <xliff:g id="APP_NAME_1">^1</xliff:g> aplikazioari?</item>
<item quantity="one">Elementu hau zaborrontzira eramateko baimena eman nahi diozu <xliff:g id="APP_NAME_0">^1</xliff:g> aplikazioari?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> elementu zaborrontzira eramaten…</item>
+ <item quantity="one">Elementua zaborrontzira eramaten…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> audio-fitxategi zaborrontzitik ateratzeko baimena eman nahi diozu <xliff:g id="APP_NAME_1">^1</xliff:g> aplikazioari?</item>
<item quantity="one">Audio-fitxategi hau zaborrontzitik ateratzeko baimena eman nahi diozu <xliff:g id="APP_NAME_0">^1</xliff:g> aplikazioari?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> audio-fitxategi zaborrontzitik ateratzen…</item>
+ <item quantity="one">Audio-fitxategia zaborrontzitik ateratzen…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> bideo zaborrontzitik ateratzeko baimena eman nahi diozu <xliff:g id="APP_NAME_1">^1</xliff:g> aplikazioari?</item>
<item quantity="one">Bideo hau zaborrontzitik ateratzeko baimena eman nahi diozu <xliff:g id="APP_NAME_0">^1</xliff:g> aplikazioari?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> bideo zaborrontzitik ateratzen…</item>
+ <item quantity="one">Bideoa zaborrontzitik ateratzen…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> argazki zaborrontzitik ateratzeko baimena eman nahi diozu <xliff:g id="APP_NAME_1">^1</xliff:g> aplikazioari?</item>
<item quantity="one">Argazki hau zaborrontzitik ateratzeko baimena eman nahi diozu <xliff:g id="APP_NAME_0">^1</xliff:g> aplikazioari?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> argazki zaborrontzitik ateratzen…</item>
+ <item quantity="one">Argazkia zaborrontzitik ateratzen…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> elementu zaborrontzitik ateratzeko baimena eman nahi diozu <xliff:g id="APP_NAME_1">^1</xliff:g> aplikazioari?</item>
<item quantity="one">Elementu hau zaborrontzitik ateratzeko baimena eman nahi diozu <xliff:g id="APP_NAME_0">^1</xliff:g> aplikazioari?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> elementu zaborrontzitik ateratzen…</item>
+ <item quantity="one">Elementua zaborrontzitik ateratzen…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> audio-fitxategi ezabatzeko baimena eman nahi diozu <xliff:g id="APP_NAME_1">^1</xliff:g> aplikazioari?</item>
<item quantity="one">Audio-fitxategi hau ezabatzeko baimena eman nahi diozu <xliff:g id="APP_NAME_0">^1</xliff:g> aplikazioari?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> audio-fitxategi ezabatzen…</item>
+ <item quantity="one">Audio-fitxategia ezabatzen…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> bideo ezabatzeko baimena eman nahi diozu <xliff:g id="APP_NAME_1">^1</xliff:g> aplikazioari?</item>
<item quantity="one">Bideo hau ezabatzeko baimena eman nahi diozu <xliff:g id="APP_NAME_0">^1</xliff:g> aplikazioari?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> bideo ezabatzen…</item>
+ <item quantity="one">Bideoa ezabatzen…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> argazki ezabatzeko baimena eman nahi diozu <xliff:g id="APP_NAME_1">^1</xliff:g> aplikazioari?</item>
<item quantity="one">Argazki hau ezabatzeko baimena eman nahi diozu <xliff:g id="APP_NAME_0">^1</xliff:g> aplikazioari?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> argazki ezabatzen…</item>
+ <item quantity="one">Argazkia ezabatzen…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> elementu ezabatzeko baimena eman nahi diozu <xliff:g id="APP_NAME_1">^1</xliff:g> aplikazioari?</item>
<item quantity="one">Elementu hau ezabatzeko baimena eman nahi diozu <xliff:g id="APP_NAME_0">^1</xliff:g> aplikazioari?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> elementu ezabatzen…</item>
+ <item quantity="one">Elementua ezabatzen…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> aplikazioak ezin ditu prozesatu multimedia-fitxategiak"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Bertan behera utzi da multimedia-edukiaren prozesamendua"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Errore bat gertatu da multimedia-edukia prozesatzean"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Prozesatu da multimedia-edukia"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Hasi da multimedia-edukiaren prozesamendua"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Multimedia-edukia prozesatzen…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Utzi"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Itxaron"</string>
</resources>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 63ef764..deb3250 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -47,64 +47,136 @@
<item quantity="one">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> فایل صوتی را تغییر دهد؟</item>
<item quantity="other">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> فایل صوتی را تغییر دهد؟</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="one">درحال اصلاح <xliff:g id="COUNT">^1</xliff:g> فایل صوتی…</item>
+ <item quantity="other">درحال اصلاح <xliff:g id="COUNT">^1</xliff:g> فایل صوتی…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="one">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> ویدیو را تغییر دهد؟</item>
<item quantity="other">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> ویدیو را تغییر دهد؟</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="one">درحال اصلاح <xliff:g id="COUNT">^1</xliff:g> ویدیو…</item>
+ <item quantity="other">درحال اصلاح <xliff:g id="COUNT">^1</xliff:g> ویدیو…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="one">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> عکس را تغییر دهد؟</item>
<item quantity="other">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> عکس را تغییر دهد؟</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="one">درحال اصلاح <xliff:g id="COUNT">^1</xliff:g> عکس…</item>
+ <item quantity="other">درحال اصلاح <xliff:g id="COUNT">^1</xliff:g> عکس…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="one">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> مورد را تغییر دهد؟</item>
<item quantity="other">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> مورد را تغییر دهد؟</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="one">درحال اصلاح <xliff:g id="COUNT">^1</xliff:g> مورد…</item>
+ <item quantity="other">درحال اصلاح <xliff:g id="COUNT">^1</xliff:g> مورد…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="one">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> فایل صوتی را به «حذفشدهها» منتقل کند؟</item>
<item quantity="other">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> فایل صوتی را به «حذفشدهها» منتقل کند؟</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="one">درحال انتقال <xliff:g id="COUNT">^1</xliff:g> فایل صوتی به حذفشدهها…</item>
+ <item quantity="other">درحال انتقال <xliff:g id="COUNT">^1</xliff:g> فایل صوتی به حذفشدهها…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="one">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> ویدیو را به «حذفشدهها» منتقل کند؟</item>
<item quantity="other">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> ویدیو را به «حذفشدهها» منتقل کند؟</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="one">درحال انتقال <xliff:g id="COUNT">^1</xliff:g> ویدیو به حذفشدهها…</item>
+ <item quantity="other">درحال انتقال <xliff:g id="COUNT">^1</xliff:g> ویدیو به حذفشدهها…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="one">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> عکس را به «حذفشدهها» منتقل کند؟</item>
<item quantity="other">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> عکس را به «حذفشدهها» منتقل کند؟</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="one">درحال انتقال <xliff:g id="COUNT">^1</xliff:g> عکس به حذفشدهها…</item>
+ <item quantity="other">درحال انتقال <xliff:g id="COUNT">^1</xliff:g> عکس به حذفشدهها…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="one">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> مورد را به «حذفشدهها» منتقل کند؟</item>
<item quantity="other">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> مورد را به «حذفشدهها» منتقل کند؟</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="one">درحال انتقال <xliff:g id="COUNT">^1</xliff:g> مورد به حذفشدهها…</item>
+ <item quantity="other">درحال انتقال <xliff:g id="COUNT">^1</xliff:g> مورد به حذفشدهها…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="one">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> فایل صوتی را از «حذفشدهها» خارج کند؟</item>
<item quantity="other">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> فایل صوتی را از «حذفشدهها» خارج کند؟</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="one">درحال خارج کردن <xliff:g id="COUNT">^1</xliff:g> فایل صوتی از حذفشدهها…</item>
+ <item quantity="other">درحال خارج کردن <xliff:g id="COUNT">^1</xliff:g> فایل صوتی از حذفشدهها…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="one">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> ویدیو را از «حذفشدهها» خارج کند؟</item>
<item quantity="other">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> ویدیو را از «حذفشدهها» خارج کند؟</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="one">درحال خارج کردن <xliff:g id="COUNT">^1</xliff:g> ویدیو از حذفشدهها…</item>
+ <item quantity="other">درحال خارج کردن <xliff:g id="COUNT">^1</xliff:g> ویدیو از حذفشدهها…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="one">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> عکس را از «حذفشدهها» خارج کند؟</item>
<item quantity="other">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> عکس را از «حذفشدهها» خارج کند؟</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="one">درحال خارج کردن <xliff:g id="COUNT">^1</xliff:g> عکس از حذفشدهها…</item>
+ <item quantity="other">درحال خارج کردن <xliff:g id="COUNT">^1</xliff:g> عکس از حذفشدهها…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="one">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> مورد را از «حذفشدهها» خارج کند؟</item>
<item quantity="other">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> مورد را از «حذفشدهها» خارج کند؟</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="one">درحال خارج کردن <xliff:g id="COUNT">^1</xliff:g> مورد از حذفشدهها…</item>
+ <item quantity="other">درحال خارج کردن <xliff:g id="COUNT">^1</xliff:g> مورد از حذفشدهها…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="one">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> فایل صوتی را حذف کند؟</item>
<item quantity="other">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> فایل صوتی را حذف کند؟</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="one">درحال حذف <xliff:g id="COUNT">^1</xliff:g> فایل صوتی…</item>
+ <item quantity="other">درحال حذف <xliff:g id="COUNT">^1</xliff:g> فایل صوتی…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="one">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> ویدیو را حذف کند؟</item>
<item quantity="other">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> ویدیو را حذف کند؟</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="one">درحال حذف <xliff:g id="COUNT">^1</xliff:g> ویدیو…</item>
+ <item quantity="other">درحال حذف <xliff:g id="COUNT">^1</xliff:g> ویدیو…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="one">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> عکس را حذف کند؟</item>
<item quantity="other">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> عکس را حذف کند؟</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="one">درحال حذف <xliff:g id="COUNT">^1</xliff:g> عکس…</item>
+ <item quantity="other">درحال حذف <xliff:g id="COUNT">^1</xliff:g> عکس…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="one">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> مورد را حذف کند؟</item>
<item quantity="other">به <xliff:g id="APP_NAME_1">^1</xliff:g> اجازه میدهید <xliff:g id="COUNT">^2</xliff:g> مورد را حذف کند؟</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="one">درحال حذف <xliff:g id="COUNT">^1</xliff:g> مورد…</item>
+ <item quantity="other">درحال حذف <xliff:g id="COUNT">^1</xliff:g> مورد…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> نمیتواند فایلهای رسانهای را پردازش کند"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"پردازش رسانه لغو شد"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"خطای پردازش رسانه"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"پردازش رسانه باموفقیت انجام شد"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"پردازش رسانه شروع شد"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"درحال پردازش رسانه…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"لغو"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"انتظار"</string>
</resources>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 39517ba..9e65ae7 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">Saako <xliff:g id="APP_NAME_1">^1</xliff:g> muokata <xliff:g id="COUNT">^2</xliff:g> audiotiedostoa?</item>
<item quantity="one">Saako <xliff:g id="APP_NAME_0">^1</xliff:g> muokata tätä audiotiedostoa?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other">Muokataan <xliff:g id="COUNT">^1</xliff:g> audiotiedostoa…</item>
+ <item quantity="one">Muokataan audiotiedostoa…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">Saako <xliff:g id="APP_NAME_1">^1</xliff:g> muokata <xliff:g id="COUNT">^2</xliff:g> videota?</item>
<item quantity="one">Saako <xliff:g id="APP_NAME_0">^1</xliff:g> muokata tätä videota?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other">Muokataan <xliff:g id="COUNT">^1</xliff:g> videota…</item>
+ <item quantity="one">Muokataan videota…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">Saako <xliff:g id="APP_NAME_1">^1</xliff:g> muokata <xliff:g id="COUNT">^2</xliff:g> kuvaa?</item>
<item quantity="one">Saako <xliff:g id="APP_NAME_0">^1</xliff:g> muokata tätä kuvaa?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other">Muokataan <xliff:g id="COUNT">^1</xliff:g> valokuvaa…</item>
+ <item quantity="one">Muokataan valokuvaa…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">Saako <xliff:g id="APP_NAME_1">^1</xliff:g> muokata <xliff:g id="COUNT">^2</xliff:g> kohdetta?</item>
<item quantity="one">Saako <xliff:g id="APP_NAME_0">^1</xliff:g> muokata tätä?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other">Muokataan <xliff:g id="COUNT">^1</xliff:g> kohdetta…</item>
+ <item quantity="one">Muokataan kohdetta…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">Saako <xliff:g id="APP_NAME_1">^1</xliff:g> siirtää <xliff:g id="COUNT">^2</xliff:g> audiotiedostoa roskakoriin?</item>
<item quantity="one">Saako <xliff:g id="APP_NAME_0">^1</xliff:g> siirtää tämän audiotiedoston roskakoriin?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other">Siirretään <xliff:g id="COUNT">^1</xliff:g> audiotiedostoa roskakoriin…</item>
+ <item quantity="one">Siirretään audiotiedostoa roskakoriin…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">Saako <xliff:g id="APP_NAME_1">^1</xliff:g> siirtää <xliff:g id="COUNT">^2</xliff:g> videota roskakoriin?</item>
<item quantity="one">Saako <xliff:g id="APP_NAME_0">^1</xliff:g> siirtää tämän videon roskakoriin?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other">Siirretään <xliff:g id="COUNT">^1</xliff:g> videota roskakoriin…</item>
+ <item quantity="one">Siirretään videota roskakoriin…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">Saako <xliff:g id="APP_NAME_1">^1</xliff:g> siirtää <xliff:g id="COUNT">^2</xliff:g> kuvaa roskakoriin?</item>
<item quantity="one">Saako <xliff:g id="APP_NAME_0">^1</xliff:g> siirtää tämän kuvan roskakoriin?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other">Siirretään <xliff:g id="COUNT">^1</xliff:g> valokuvaa roskakoriin…</item>
+ <item quantity="one">Siirretään valokuvaa roskakoriin…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">Saako <xliff:g id="APP_NAME_1">^1</xliff:g> siirtää <xliff:g id="COUNT">^2</xliff:g> kohdetta roskakoriin?</item>
<item quantity="one">Saako <xliff:g id="APP_NAME_0">^1</xliff:g> siirtää tämän roskakoriin?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other">Siirretään <xliff:g id="COUNT">^1</xliff:g> kohdetta roskakoriin…</item>
+ <item quantity="one">Siirretään kohdetta roskakoriin…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">Saako <xliff:g id="APP_NAME_1">^1</xliff:g> ottaa <xliff:g id="COUNT">^2</xliff:g> audiotiedostoa pois roskakorista?</item>
<item quantity="one">Saako <xliff:g id="APP_NAME_0">^1</xliff:g> ottaa tämän audiotiedoston pois roskakorista?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other">Siirretään <xliff:g id="COUNT">^1</xliff:g> audiotiedostoa pois roskakorista…</item>
+ <item quantity="one">Siirretään audiotiedostoa pois roskakorista…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">Saako <xliff:g id="APP_NAME_1">^1</xliff:g> ottaa <xliff:g id="COUNT">^2</xliff:g> videota pois roskakorista?</item>
<item quantity="one">Saako <xliff:g id="APP_NAME_0">^1</xliff:g> ottaa tämän videon pois roskakorista?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other">Siirretään <xliff:g id="COUNT">^1</xliff:g> videota pois roskakorista…</item>
+ <item quantity="one">Siirretään videota pois roskakorista…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">Saako <xliff:g id="APP_NAME_1">^1</xliff:g> ottaa <xliff:g id="COUNT">^2</xliff:g> kuvaa pois roskakorista?</item>
<item quantity="one">Saako <xliff:g id="APP_NAME_0">^1</xliff:g> ottaa tämän kuvan pois roskakorista?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other">Siirretään <xliff:g id="COUNT">^1</xliff:g> valokuvaa pois roskakorista…</item>
+ <item quantity="one">Siirretään valokuvaa pois roskakorista…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">Saako <xliff:g id="APP_NAME_1">^1</xliff:g> ottaa <xliff:g id="COUNT">^2</xliff:g> kohdetta pois roskakorista?</item>
<item quantity="one">Saako <xliff:g id="APP_NAME_0">^1</xliff:g> ottaa tämän pois roskakorista?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other">Siirretään <xliff:g id="COUNT">^1</xliff:g> kohdetta pois roskakorista…</item>
+ <item quantity="one">Siirretään kohdetta pois roskakorista…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">Saako <xliff:g id="APP_NAME_1">^1</xliff:g> poistaa <xliff:g id="COUNT">^2</xliff:g> audiotiedostoa?</item>
<item quantity="one">Saako <xliff:g id="APP_NAME_0">^1</xliff:g> poistaa tämän audiotiedoston?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other">Poistetaan <xliff:g id="COUNT">^1</xliff:g> audiotiedostoa…</item>
+ <item quantity="one">Poistetaan audiotiedostoa…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">Saako <xliff:g id="APP_NAME_1">^1</xliff:g> poistaa <xliff:g id="COUNT">^2</xliff:g> videota?</item>
<item quantity="one">Saako <xliff:g id="APP_NAME_0">^1</xliff:g> poistaa tämän videon?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other">Poistetaan <xliff:g id="COUNT">^1</xliff:g> videota…</item>
+ <item quantity="one">Poistetaan videota…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">Saako <xliff:g id="APP_NAME_1">^1</xliff:g> poistaa <xliff:g id="COUNT">^2</xliff:g> kuvaa?</item>
<item quantity="one">Saako <xliff:g id="APP_NAME_0">^1</xliff:g> poistaa tämän kuvan?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other">Poistetaan <xliff:g id="COUNT">^1</xliff:g> valokuvaa…</item>
+ <item quantity="one">Poistetaan valokuvaa…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">Saako <xliff:g id="APP_NAME_1">^1</xliff:g> poistaa <xliff:g id="COUNT">^2</xliff:g> kohdetta?</item>
<item quantity="one">Saako <xliff:g id="APP_NAME_0">^1</xliff:g> poistaa tämän?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other">Poistetaan <xliff:g id="COUNT">^1</xliff:g> kohdetta…</item>
+ <item quantity="one">Poistetaan kohdetta…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> ei voi käsitellä mediatiedostoja"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Mediasisällön käsittely peruttiin"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Virhe mediasisällön käsittelyssä"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Mediasisällön käsittely onnistui"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Mediasisällön käsittely alkoi"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Käsitellään mediasisältöä…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Peru"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Odota"</string>
</resources>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 021ba70..de7245c 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -47,64 +47,136 @@
<item quantity="one">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à modifier <xliff:g id="COUNT">^2</xliff:g> fichier audio?</item>
<item quantity="other">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à modifier <xliff:g id="COUNT">^2</xliff:g> fichiers audio?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="one">Modification de <xliff:g id="COUNT">^1</xliff:g> fichier audio en cours…</item>
+ <item quantity="other">Modification de <xliff:g id="COUNT">^1</xliff:g> fichiers audio en cours…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="one">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à modifier <xliff:g id="COUNT">^2</xliff:g> vidéo?</item>
<item quantity="other">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à modifier <xliff:g id="COUNT">^2</xliff:g> vidéos?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="one">Modification de <xliff:g id="COUNT">^1</xliff:g> vidéo en cours…</item>
+ <item quantity="other">Modification de <xliff:g id="COUNT">^1</xliff:g> vidéos en cours…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="one">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à modifier <xliff:g id="COUNT">^2</xliff:g> photo?</item>
<item quantity="other">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à modifier <xliff:g id="COUNT">^2</xliff:g> photos?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="one">Modification de <xliff:g id="COUNT">^1</xliff:g> photo en cours…</item>
+ <item quantity="other">Modification de <xliff:g id="COUNT">^1</xliff:g> photos en cours…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="one">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à modifier <xliff:g id="COUNT">^2</xliff:g> élément?</item>
<item quantity="other">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à modifier <xliff:g id="COUNT">^2</xliff:g> éléments?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="one">Modification de <xliff:g id="COUNT">^1</xliff:g> élément en cours…</item>
+ <item quantity="other">Modification de <xliff:g id="COUNT">^1</xliff:g> éléments en cours…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="one">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à déplacer <xliff:g id="COUNT">^2</xliff:g> fichier audio dans la corbeille?</item>
<item quantity="other">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à déplacer <xliff:g id="COUNT">^2</xliff:g> fichiers audio dans la corbeille?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="one">Déplacement de <xliff:g id="COUNT">^1</xliff:g> fichier audio vers la corbeille en cours…</item>
+ <item quantity="other">Déplacement de <xliff:g id="COUNT">^1</xliff:g> fichiers audio vers la corbeille en cours…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="one">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à déplacer <xliff:g id="COUNT">^2</xliff:g> vidéo dans la corbeille?</item>
<item quantity="other">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à déplacer <xliff:g id="COUNT">^2</xliff:g> vidéos dans la corbeille?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="one">Déplacement de <xliff:g id="COUNT">^1</xliff:g> vidéo vers la corbeille en cours…</item>
+ <item quantity="other">Déplacement de <xliff:g id="COUNT">^1</xliff:g> vidéos vers la corbeille en cours…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="one">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à déplacer <xliff:g id="COUNT">^2</xliff:g> photo dans la corbeille?</item>
<item quantity="other">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à déplacer <xliff:g id="COUNT">^2</xliff:g> photos dans la corbeille?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="one">Déplacement de <xliff:g id="COUNT">^1</xliff:g> photo vers la corbeille en cours…</item>
+ <item quantity="other">Déplacement de <xliff:g id="COUNT">^1</xliff:g> photos vers la corbeille en cours…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="one">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à déplacer <xliff:g id="COUNT">^2</xliff:g> élément dans la corbeille?</item>
<item quantity="other">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à déplacer <xliff:g id="COUNT">^2</xliff:g> éléments dans la corbeille?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="one">Déplacement de <xliff:g id="COUNT">^1</xliff:g> élément vers la corbeille en cours…</item>
+ <item quantity="other">Déplacement de <xliff:g id="COUNT">^1</xliff:g> éléments vers la corbeille en cours…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="one">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à restaurer <xliff:g id="COUNT">^2</xliff:g> fichier audio de la corbeille?</item>
<item quantity="other">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à restaurer <xliff:g id="COUNT">^2</xliff:g> fichiers audio de la corbeille?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="one">Restauration de <xliff:g id="COUNT">^1</xliff:g> fichier audio de la corbeille en cours…</item>
+ <item quantity="other">Restauration de <xliff:g id="COUNT">^1</xliff:g> fichiers audio de la corbeille en cours…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="one">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à restaurer <xliff:g id="COUNT">^2</xliff:g> vidéo de la corbeille?</item>
<item quantity="other">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à restaurer <xliff:g id="COUNT">^2</xliff:g> vidéos de la corbeille?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="one">Restauration de <xliff:g id="COUNT">^1</xliff:g> vidéo de la corbeille en cours…</item>
+ <item quantity="other">Restauration de <xliff:g id="COUNT">^1</xliff:g> vidéos de la corbeille en cours…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="one">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à restaurer <xliff:g id="COUNT">^2</xliff:g> photo de la corbeille?</item>
<item quantity="other">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à restaurer <xliff:g id="COUNT">^2</xliff:g> photos de la corbeille?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="one">Restauration de <xliff:g id="COUNT">^1</xliff:g> photo de la corbeille en cours…</item>
+ <item quantity="other">Restauration de <xliff:g id="COUNT">^1</xliff:g> photos de la corbeille en cours…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="one">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à restaurer <xliff:g id="COUNT">^2</xliff:g> élément de la corbeille?</item>
<item quantity="other">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à restaurer <xliff:g id="COUNT">^2</xliff:g> éléments de la corbeille?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="one">Restauration de <xliff:g id="COUNT">^1</xliff:g> élément de la corbeille en cours…</item>
+ <item quantity="other">Restauration de <xliff:g id="COUNT">^1</xliff:g> éléments de la corbeille en cours…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="one">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à supprimer <xliff:g id="COUNT">^2</xliff:g> fichier audio?</item>
<item quantity="other">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à supprimer <xliff:g id="COUNT">^2</xliff:g> fichiers audio?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="one">Suppression de <xliff:g id="COUNT">^1</xliff:g> fichier audio en cours…</item>
+ <item quantity="other">Suppression de <xliff:g id="COUNT">^1</xliff:g> fichiers audio en cours…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="one">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à supprimer <xliff:g id="COUNT">^2</xliff:g> vidéo?</item>
<item quantity="other">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à supprimer <xliff:g id="COUNT">^2</xliff:g> vidéos?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="one">Suppression de <xliff:g id="COUNT">^1</xliff:g> vidéo en cours…</item>
+ <item quantity="other">Suppression de <xliff:g id="COUNT">^1</xliff:g> vidéos en cours…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="one">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à supprimer <xliff:g id="COUNT">^2</xliff:g> photo?</item>
<item quantity="other">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à supprimer <xliff:g id="COUNT">^2</xliff:g> photos?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="one">Suppression de <xliff:g id="COUNT">^1</xliff:g> photo en cours…</item>
+ <item quantity="other">Suppression de <xliff:g id="COUNT">^1</xliff:g> photos en cours…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="one">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à supprimer <xliff:g id="COUNT">^2</xliff:g> élément?</item>
<item quantity="other">Autoriser <xliff:g id="APP_NAME_1">^1</xliff:g> à supprimer <xliff:g id="COUNT">^2</xliff:g> éléments?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="one">Suppression de <xliff:g id="COUNT">^1</xliff:g> élément en cours…</item>
+ <item quantity="other">Suppression de <xliff:g id="COUNT">^1</xliff:g> éléments en cours…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> ne peut pas traiter les fichiers multimédias"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Le traitement du contenu multimédia a été annulé"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Une erreur s\'est produite durant le traitement du contenu multimédia"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Le traitement du contenu multimédia a réussi"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Le traitement du contenu multimédia a démarré"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Traitement du contenu multimédia en cours…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Annuler"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Patienter"</string>
</resources>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 7b0d694..c995739 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -47,64 +47,136 @@
<item quantity="one">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à modifier <xliff:g id="COUNT">^2</xliff:g> fichier audio ?</item>
<item quantity="other">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à modifier <xliff:g id="COUNT">^2</xliff:g> fichiers audio ?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="one">Modification de <xliff:g id="COUNT">^1</xliff:g> fichier audio…</item>
+ <item quantity="other">Modification de <xliff:g id="COUNT">^1</xliff:g> fichiers audio…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="one">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à modifier <xliff:g id="COUNT">^2</xliff:g> vidéo ?</item>
<item quantity="other">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à modifier <xliff:g id="COUNT">^2</xliff:g> vidéos ?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="one">Modification de <xliff:g id="COUNT">^1</xliff:g> vidéo…</item>
+ <item quantity="other">Modification de <xliff:g id="COUNT">^1</xliff:g> vidéos…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="one">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à modifier <xliff:g id="COUNT">^2</xliff:g> photo ?</item>
<item quantity="other">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à modifier <xliff:g id="COUNT">^2</xliff:g> photos ?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="one">Modification de <xliff:g id="COUNT">^1</xliff:g> photo…</item>
+ <item quantity="other">Modification de <xliff:g id="COUNT">^1</xliff:g> photos…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="one">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à modifier <xliff:g id="COUNT">^2</xliff:g> élément ?</item>
<item quantity="other">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à modifier <xliff:g id="COUNT">^2</xliff:g> éléments ?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="one">Modification de <xliff:g id="COUNT">^1</xliff:g> élément…</item>
+ <item quantity="other">Modification de <xliff:g id="COUNT">^1</xliff:g> éléments…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="one">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à placer <xliff:g id="COUNT">^2</xliff:g> fichier audio dans la corbeille ?</item>
<item quantity="other">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à placer <xliff:g id="COUNT">^2</xliff:g> fichiers audio dans la corbeille ?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="one">Placement de <xliff:g id="COUNT">^1</xliff:g> fichier audio dans la corbeille…</item>
+ <item quantity="other">Placement de <xliff:g id="COUNT">^1</xliff:g> fichiers audio dans la corbeille…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="one">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à placer <xliff:g id="COUNT">^2</xliff:g> vidéo dans la corbeille ?</item>
<item quantity="other">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à placer <xliff:g id="COUNT">^2</xliff:g> vidéos dans la corbeille ?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="one">Placement de <xliff:g id="COUNT">^1</xliff:g> vidéo dans la corbeille…</item>
+ <item quantity="other">Placement de <xliff:g id="COUNT">^1</xliff:g> vidéos dans la corbeille…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="one">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à placer <xliff:g id="COUNT">^2</xliff:g> photo dans la corbeille ?</item>
<item quantity="other">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à placer <xliff:g id="COUNT">^2</xliff:g> photos dans la corbeille ?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="one">Placement de <xliff:g id="COUNT">^1</xliff:g> photo dans la corbeille…</item>
+ <item quantity="other">Placement de <xliff:g id="COUNT">^1</xliff:g> photos dans la corbeille…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="one">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à placer <xliff:g id="COUNT">^2</xliff:g> élément dans la corbeille ?</item>
<item quantity="other">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à placer <xliff:g id="COUNT">^2</xliff:g> éléments dans la corbeille ?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="one">Placement de <xliff:g id="COUNT">^1</xliff:g> élément dans la corbeille…</item>
+ <item quantity="other">Placement de <xliff:g id="COUNT">^1</xliff:g> éléments dans la corbeille…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="one">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à retirer <xliff:g id="COUNT">^2</xliff:g> fichier audio de la corbeille ?</item>
<item quantity="other">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à retirer <xliff:g id="COUNT">^2</xliff:g> fichiers audio de la corbeille ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="one">Retrait de <xliff:g id="COUNT">^1</xliff:g> fichier audio de la corbeille…</item>
+ <item quantity="other">Retrait de <xliff:g id="COUNT">^1</xliff:g> fichiers audio de la corbeille…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="one">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à retirer <xliff:g id="COUNT">^2</xliff:g> vidéo de la corbeille ?</item>
<item quantity="other">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à retirer <xliff:g id="COUNT">^2</xliff:g> vidéos de la corbeille ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="one">Retrait de <xliff:g id="COUNT">^1</xliff:g> vidéo de la corbeille…</item>
+ <item quantity="other">Retrait de <xliff:g id="COUNT">^1</xliff:g> vidéos de la corbeille…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="one">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à retirer <xliff:g id="COUNT">^2</xliff:g> photo de la corbeille ?</item>
<item quantity="other">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à retirer <xliff:g id="COUNT">^2</xliff:g> photos de la corbeille ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="one">Retrait de <xliff:g id="COUNT">^1</xliff:g> photo de la corbeille…</item>
+ <item quantity="other">Retrait de <xliff:g id="COUNT">^1</xliff:g> photos de la corbeille…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="one">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à retirer <xliff:g id="COUNT">^2</xliff:g> élément de la corbeille ?</item>
<item quantity="other">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à retirer <xliff:g id="COUNT">^2</xliff:g> éléments de la corbeille ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="one">Retrait de <xliff:g id="COUNT">^1</xliff:g> élément de la corbeille…</item>
+ <item quantity="other">Retrait de <xliff:g id="COUNT">^1</xliff:g> éléments de la corbeille…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="one">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à supprimer <xliff:g id="COUNT">^2</xliff:g> fichier audio ?</item>
<item quantity="other">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à supprimer <xliff:g id="COUNT">^2</xliff:g> fichiers audio ?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="one">Suppression de <xliff:g id="COUNT">^1</xliff:g> fichier audio…</item>
+ <item quantity="other">Suppression de <xliff:g id="COUNT">^1</xliff:g> fichiers audio…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="one">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à supprimer <xliff:g id="COUNT">^2</xliff:g> vidéo ?</item>
<item quantity="other">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à supprimer <xliff:g id="COUNT">^2</xliff:g> vidéos ?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="one">Suppression de <xliff:g id="COUNT">^1</xliff:g> vidéo…</item>
+ <item quantity="other">Suppression de <xliff:g id="COUNT">^1</xliff:g> vidéos…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="one">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à supprimer <xliff:g id="COUNT">^2</xliff:g> photo ?</item>
<item quantity="other">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à supprimer <xliff:g id="COUNT">^2</xliff:g> photos ?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="one">Suppression de <xliff:g id="COUNT">^1</xliff:g> photo…</item>
+ <item quantity="other">Suppression de <xliff:g id="COUNT">^1</xliff:g> photos…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="one">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à supprimer <xliff:g id="COUNT">^2</xliff:g> élément ?</item>
<item quantity="other">Autoriser l\'application <xliff:g id="APP_NAME_1">^1</xliff:g> à supprimer <xliff:g id="COUNT">^2</xliff:g> éléments ?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="one">Suppression de <xliff:g id="COUNT">^1</xliff:g> élément…</item>
+ <item quantity="other">Suppression de <xliff:g id="COUNT">^1</xliff:g> éléments…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> ne peut pas traiter les fichiers multimédias"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Traitement des contenus multimédias annulé"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Erreur de traitement des contenus multimédias"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Le traitement des contenus multimédias a réussi"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Le traitement des contenus multimédias a commencé"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Traitement des contenus multimédias…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Annuler"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Attendre"</string>
</resources>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 93e281d..aa53246 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">Queres permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> ficheiros de audio?</item>
<item quantity="one">Queres permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> modifique este ficheiro de audio?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other">Modificando <xliff:g id="COUNT">^1</xliff:g> ficheiros de audio…</item>
+ <item quantity="one">Modificando 1 ficheiro de audio…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">Queres permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> vídeos?</item>
<item quantity="one">Queres permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> modifique este vídeo?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other">Modificando <xliff:g id="COUNT">^1</xliff:g> vídeos…</item>
+ <item quantity="one">Modificando 1 vídeo…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">Queres permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> fotos?</item>
<item quantity="one">Queres permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> modifique esta foto?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other">Modificando <xliff:g id="COUNT">^1</xliff:g> fotos…</item>
+ <item quantity="one">Modificando 1 foto…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">Queres permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> elementos?</item>
<item quantity="one">Queres permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> modifique este elemento?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other">Modificando <xliff:g id="COUNT">^1</xliff:g> elementos…</item>
+ <item quantity="one">Modificando 1 elemento…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">Queres permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> mova <xliff:g id="COUNT">^2</xliff:g> ficheiros de audio á papeleira?</item>
<item quantity="one">Queres permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> mova este ficheiro de audio á papeleira?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other">Movendo <xliff:g id="COUNT">^1</xliff:g> ficheiros de audio á papeleira…</item>
+ <item quantity="one">Movendo 1 ficheiro de audio á papeleira…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">Queres permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> mova <xliff:g id="COUNT">^2</xliff:g> vídeos á papeleira?</item>
<item quantity="one">Queres permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> mova este vídeo á papeleira?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other">Movendo <xliff:g id="COUNT">^1</xliff:g> vídeos á papeleira…</item>
+ <item quantity="one">Movendo 1 vídeo á papeleira…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">Queres permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> mova <xliff:g id="COUNT">^2</xliff:g> fotos á papeleira?</item>
<item quantity="one">Queres permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> mova esta foto á papeleira?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other">Movendo <xliff:g id="COUNT">^1</xliff:g> fotos á papeleira…</item>
+ <item quantity="one">Movendo 1 foto á papeleira…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">Queres permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> mova <xliff:g id="COUNT">^2</xliff:g> elementos á papeleira?</item>
<item quantity="one">Queres permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> mova este elemento á papeleira?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other">Movendo <xliff:g id="COUNT">^1</xliff:g> elementos á papeleira…</item>
+ <item quantity="one">Movendo 1 elemento á papeleira…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">Queres permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> saque <xliff:g id="COUNT">^2</xliff:g> ficheiros de audio da papeleira?</item>
<item quantity="one">Queres permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> saque este ficheiro de audio da papeleira?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other">Sacando <xliff:g id="COUNT">^1</xliff:g> ficheiros de audio da papeleira…</item>
+ <item quantity="one">Sacando 1 ficheiro de audio da papeleira…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">Queres permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> saque <xliff:g id="COUNT">^2</xliff:g> vídeos da papeleira?</item>
<item quantity="one">Queres permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> saque este vídeo da papeleira?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other">Sacando <xliff:g id="COUNT">^1</xliff:g> vídeos da papeleira…</item>
+ <item quantity="one">Sacando 1 vídeo da papeleira…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">Queres permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> saque <xliff:g id="COUNT">^2</xliff:g> fotos da papeleira?</item>
<item quantity="one">Queres permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> saque esta foto da papeleira?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other">Sacando <xliff:g id="COUNT">^1</xliff:g> fotos da papeleira…</item>
+ <item quantity="one">Sacando 1 foto da papeleira…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">Queres permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> saque <xliff:g id="COUNT">^2</xliff:g> elementos da papeleira?</item>
<item quantity="one">Queres permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> saque este elemento da papeleira?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other">Sacando <xliff:g id="COUNT">^1</xliff:g> elementos da papeleira…</item>
+ <item quantity="one">Sacando 1 elemento da papeleira…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">Queres permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> elimine <xliff:g id="COUNT">^2</xliff:g> ficheiros de audio?</item>
<item quantity="one">Queres permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> elimine este ficheiro de audio?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other">Eliminando <xliff:g id="COUNT">^1</xliff:g> ficheiros de audio…</item>
+ <item quantity="one">Eliminando 1 ficheiro de audio…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">Queres permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> elimine <xliff:g id="COUNT">^2</xliff:g> vídeos?</item>
<item quantity="one">Queres permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> elimine este vídeo?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other">Eliminando <xliff:g id="COUNT">^1</xliff:g> vídeos…</item>
+ <item quantity="one">Eliminando 1 vídeo…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">Queres permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> elimine <xliff:g id="COUNT">^2</xliff:g> fotos?</item>
<item quantity="one">Queres permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> elimine esta foto?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other">Eliminando <xliff:g id="COUNT">^1</xliff:g> fotos…</item>
+ <item quantity="one">Eliminando 1 foto…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">Queres permitir que <xliff:g id="APP_NAME_1">^1</xliff:g> elimine <xliff:g id="COUNT">^2</xliff:g> elementos?</item>
<item quantity="one">Queres permitir que <xliff:g id="APP_NAME_0">^1</xliff:g> elimine este elemento?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other">Eliminando <xliff:g id="COUNT">^1</xliff:g> elementos…</item>
+ <item quantity="one">Eliminando 1 elemento…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> non pode procesar ficheiros multimedia"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Cancelouse o procesamento do contido multimedia"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Produciuse un erro no procesamento do contido multimedia"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Realizouse correctamente o procesamento do contido multimedia"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Iniciouse o procesamento do contido multimedia"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Procesando contido multimedia…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Cancelar"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Esperar"</string>
</resources>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index d7cc37d..3cffaf6 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -47,64 +47,136 @@
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ને <xliff:g id="COUNT">^2</xliff:g> ઑડિયો ફાઇલમાં ફેરફાર કરવાની મંજૂરી આપીએ?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ને <xliff:g id="COUNT">^2</xliff:g> ઑડિયો ફાઇલમાં ફેરફાર કરવાની મંજૂરી આપીએ?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ઑડિયો ફાઇલમાં ફેરફાર કરી રહ્યાં છીએ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ઑડિયો ફાઇલમાં ફેરફાર કરી રહ્યાં છીએ…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ને <xliff:g id="COUNT">^2</xliff:g> વીડિયોમાં ફેરફાર કરવાની મંજૂરી આપીએ?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ને <xliff:g id="COUNT">^2</xliff:g> વીડિયોમાં ફેરફાર કરવાની મંજૂરી આપીએ?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> વીડિયોમાં ફેરફાર કરી રહ્યાં છીએ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> વીડિયોમાં ફેરફાર કરી રહ્યાં છીએ…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ને <xliff:g id="COUNT">^2</xliff:g> ફોટામાં ફેરફાર કરવાની મંજૂરી આપીએ?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ને <xliff:g id="COUNT">^2</xliff:g> ફોટામાં ફેરફાર કરવાની મંજૂરી આપીએ?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ફોટોમાં ફેરફાર કરી રહ્યાં છીએ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ફોટોમાં ફેરફાર કરી રહ્યાં છીએ…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ને <xliff:g id="COUNT">^2</xliff:g> આઇટમમાં ફેરફાર કરવાની મંજૂરી આપીએ?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ને <xliff:g id="COUNT">^2</xliff:g> આઇટમમાં ફેરફાર કરવાની મંજૂરી આપીએ?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> આઇટમમાં ફેરફાર કરી રહ્યાં છીએ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> આઇટમમાં ફેરફાર કરી રહ્યાં છીએ…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ને <xliff:g id="COUNT">^2</xliff:g> ઑડિયો ફાઇલને ટ્રેશમાં ખસેડવાની મંજૂરી આપીએ?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ને <xliff:g id="COUNT">^2</xliff:g> ઑડિયો ફાઇલને ટ્રેશમાં ખસેડવાની મંજૂરી આપીએ?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ઑડિયો ફાઇલ ટ્રેશમાં ખસેડી રહ્યાં છીએ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ઑડિયો ફાઇલ ટ્રેશમાં ખસેડી રહ્યાં છીએ…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ને <xliff:g id="COUNT">^2</xliff:g> વીડિયોને ટ્રેશમાં ખસેડવાની મંજૂરી આપીએ?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ને <xliff:g id="COUNT">^2</xliff:g> વીડિયોને ટ્રેશમાં ખસેડવાની મંજૂરી આપીએ?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> વીડિયો ટ્રેશમાં ખસેડી રહ્યાં છીએ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> વીડિયો ટ્રેશમાં ખસેડી રહ્યાં છીએ…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ને <xliff:g id="COUNT">^2</xliff:g> ફોટાને ટ્રેશમાં ખસેડવાની મંજૂરી આપીએ?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ને <xliff:g id="COUNT">^2</xliff:g> ફોટાને ટ્રેશમાં ખસેડવાની મંજૂરી આપીએ?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ફોટો ટ્રેશમાં ખસેડી રહ્યાં છીએ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ફોટો ટ્રેશમાં ખસેડી રહ્યાં છીએ…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ને <xliff:g id="COUNT">^2</xliff:g> આઇટમને ટ્રેશમાં ખસેડવાની મંજૂરી આપીએ?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ને <xliff:g id="COUNT">^2</xliff:g> આઇટમને ટ્રેશમાં ખસેડવાની મંજૂરી આપીએ?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> આઇટમ ટ્રેશમાં ખસેડી રહ્યાં છીએ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> આઇટમ ટ્રેશમાં ખસેડી રહ્યાં છીએ…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ને <xliff:g id="COUNT">^2</xliff:g> ઑડિયો ફાઇલને ટ્રેશમાંથી બહાર લાવવાની મંજૂરી આપીએ?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ને <xliff:g id="COUNT">^2</xliff:g> ઑડિયો ફાઇલને ટ્રેશમાંથી બહાર લાવવાની મંજૂરી આપીએ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ઑડિયો ફાઇલ ટ્રેશમાંથી બહાર ખસેડી રહ્યાં છીએ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ઑડિયો ફાઇલ ટ્રેશમાંથી બહાર ખસેડી રહ્યાં છીએ…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ને <xliff:g id="COUNT">^2</xliff:g> વીડિયોને ટ્રેશમાંથી બહાર લાવવાની મંજૂરી આપીએ?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ને <xliff:g id="COUNT">^2</xliff:g> વીડિયોને ટ્રેશમાંથી બહાર લાવવાની મંજૂરી આપીએ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> વીડિયો ટ્રેશમાંથી બહાર ખસેડી રહ્યાં છીએ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> વીડિયો ટ્રેશમાંથી બહાર ખસેડી રહ્યાં છીએ…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ને <xliff:g id="COUNT">^2</xliff:g> ફોટાને ટ્રેશમાંથી બહાર લાવવાની મંજૂરી આપીએ?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ને <xliff:g id="COUNT">^2</xliff:g> ફોટાને ટ્રેશમાંથી બહાર લાવવાની મંજૂરી આપીએ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ફોટો ટ્રેશમાંથી બહાર ખસેડી રહ્યાં છીએ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ફોટો ટ્રેશમાંથી બહાર ખસેડી રહ્યાં છીએ…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ને <xliff:g id="COUNT">^2</xliff:g> આઇટમને ટ્રેશમાંથી બહાર લાવવાની મંજૂરી આપીએ?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ને <xliff:g id="COUNT">^2</xliff:g> આઇટમને ટ્રેશમાંથી બહાર લાવવાની મંજૂરી આપીએ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> આઇટમ ટ્રેશમાંથી બહાર ખસેડી રહ્યાં છીએ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> આઇટમ ટ્રેશમાંથી બહાર ખસેડી રહ્યાં છીએ…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ને આ <xliff:g id="COUNT">^2</xliff:g> ઑડિયો ફાઇલ ડિલીટ કરવાની મંજૂરી આપીએ?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ને આ <xliff:g id="COUNT">^2</xliff:g> ઑડિયો ફાઇલ ડિલીટ કરવાની મંજૂરી આપીએ?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ઑડિયો ફાઇલ ડિલીટ કરી રહ્યાં છીએ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ઑડિયો ફાઇલ ડિલીટ કરી રહ્યાં છીએ…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ને આ <xliff:g id="COUNT">^2</xliff:g> વીડિયો ડિલીટ કરવાની મંજૂરી આપીએ?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ને આ <xliff:g id="COUNT">^2</xliff:g> વીડિયો ડિલીટ કરવાની મંજૂરી આપીએ?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> વીડિયો ડિલીટ કરી રહ્યાં છીએ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> વીડિયો ડિલીટ કરી રહ્યાં છીએ…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ને આ <xliff:g id="COUNT">^2</xliff:g> ફોટો ડિલીટ કરવાની મંજૂરી આપીએ?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ને આ <xliff:g id="COUNT">^2</xliff:g> ફોટો ડિલીટ કરવાની મંજૂરી આપીએ?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ફોટો ડિલીટ કરી રહ્યાં છીએ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ફોટો ડિલીટ કરી રહ્યાં છીએ…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ને આ <xliff:g id="COUNT">^2</xliff:g> આઇટમ ડિલીટ કરવાની મંજૂરી આપીએ?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ને આ <xliff:g id="COUNT">^2</xliff:g> આઇટમ ડિલીટ કરવાની મંજૂરી આપીએ?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> આઇટમ ડિલીટ કરી રહ્યાં છીએ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> આઇટમ ડિલીટ કરી રહ્યાં છીએ…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> મીડિયા ફાઇલો પર પ્રક્રિયા કરી શકતું નથી"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"મીડિયા પર થતી પ્રક્રિયા રદ કરવામાં આવી"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"મીડિયા પર થતી પ્રક્રિયામાં ભૂલ આવી"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"મીડિયા પર પ્રક્રિયા કરવાનું સફળ થયું"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"મીડિયા પર પ્રક્રિયા શરૂ કરવામાં આવી"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"મીડિયા પર પ્રક્રિયા થઈ રહી છે…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"રદ કરો"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"રાહ જુઓ"</string>
</resources>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 3937bd2..5881984 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -47,64 +47,136 @@
<item quantity="one">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> ऑडियो फ़ाइल में बदलाव करने की अनुमति देना चाहते हैं?</item>
<item quantity="other">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> ऑडियो फ़ाइलों में बदलाव करने की अनुमति देना चाहते हैं?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ऑडियो फ़ाइल में बदलाव किया जा रहा है…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ऑडियो फ़ाइलों में बदलाव किए जा रहे हैं…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="one">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> वीडियो में बदलाव करने की अनुमति देना चाहते हैं?</item>
<item quantity="other">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> वीडियो में बदलाव करने की अनुमति देना चाहते हैं?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> वीडियो में बदलाव किया जा रहा है…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> वीडियो में बदलाव किए जा रहे हैं…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="one">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> फ़ोटो में बदलाव करने की अनुमति देना चाहते हैं?</item>
<item quantity="other">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> फ़ोटो में बदलाव करने की अनुमति देना चाहते हैं?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> फ़ोटो में बदलाव किया जा रहा है…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> फ़ोटो में बदलाव किए जा रहे हैं…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="one">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> आइटम में बदलाव करने की अनुमति देना चाहते हैं?</item>
<item quantity="other">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> आइटम में बदलाव करने की अनुमति देना चाहते हैं?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> आइटम में बदलाव किया जा रहा है…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> आइटम में बदलाव किए जा रहे हैं…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="one">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> ऑडियो फ़ाइल, ट्रैश में मूव करने की अनुमति देना चाहते हैं?</item>
<item quantity="other">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> ऑडियो फ़ाइलें, ट्रैश में मूव करने की अनुमति देना चाहते हैं?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ऑडियो फ़ाइल को ट्रैश में भेजा जा रहा है…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ऑडियो फ़ाइलों को ट्रैश में भेजा जा रहा है…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="one">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> वीडियो, ट्रैश में मूव करने की अनुमति देना चाहते हैं?</item>
<item quantity="other">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> वीडियो, ट्रैश में मूव करने की अनुमति देना चाहते हैं?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> वीडियो को ट्रैश में भेजा जा रहा है…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> वीडियो को ट्रैश में भेजा जा रहा है…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="one">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> फ़ोटो, ट्रैश में मूव करने की अनुमति देना चाहते हैं?</item>
<item quantity="other">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> फ़ोटो, ट्रैश में मूव करने की अनुमति देना चाहते हैं?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> फ़ोटो को ट्रैश में भेजा जा रहा है…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> फ़ोटो को ट्रैश में भेजा जा रहा है…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="one">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> आइटम, ट्रैश में मूव करने की अनुमति देना चाहते हैं?</item>
<item quantity="other">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> आइटम, ट्रैश में मूव करने की अनुमति देना चाहते हैं?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> आइटम को ट्रैश में भेजा जा रहा है…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> आइटम को ट्रैश में भेजा जा रहा है…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="one">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> ऑडियो फ़ाइल, ट्रैश से बाहर निकालने की अनुमति देना चाहते हैं?</item>
<item quantity="other">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> ऑडियो फ़ाइलें, ट्रैश से बाहर निकालने की अनुमति देना चाहते हैं?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ऑडियो फ़ाइल को ट्रैश से बाहर निकाला जा रहा है…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ऑडियो फ़ाइलों को ट्रैश से बाहर निकाला जा रहा है…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="one">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> वीडियो, ट्रैश से बाहर निकालने की अनुमति देना चाहते हैं?</item>
<item quantity="other">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> वीडियो, ट्रैश से बाहर निकालने की अनुमति देना चाहते हैं?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> वीडियो को ट्रैश से बाहर निकाला जा रहा है…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> वीडियो को ट्रैश से बाहर निकाला जा रहा है…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="one">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> फ़ोटो, ट्रैश से बाहर निकालने की अनुमति देना चाहते हैं?</item>
<item quantity="other">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> फ़ोटो, ट्रैश से बाहर निकालने की अनुमति देना चाहते हैं?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> फ़ोटो को ट्रैश से बाहर निकाला जा रहा है…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> फ़ोटो को ट्रैश से बाहर निकाला जा रहा है…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="one">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> आइटम, ट्रैश से बाहर निकालने की अनुमति देना चाहते हैं?</item>
<item quantity="other">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> आइटम, ट्रैश से बाहर निकालने की अनुमति देना चाहते हैं?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> आइटम को ट्रैश से बाहर निकाला जा रहा है…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> आइटम को ट्रैश से बाहर निकाला जा रहा है…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="one">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> ऑडियो फ़ाइल मिटाने की अनुमति देना चाहते हैं?</item>
<item quantity="other">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> ऑडियो फ़ाइलें मिटाने की अनुमति देना चाहते हैं?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ऑडियो फ़ाइल मिटाई जा रही है…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ऑडियो फ़ाइलें मिटाई जा रही हैं…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="one">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> वीडियो मिटाने की अनुमति देना चाहते हैं?</item>
<item quantity="other">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> वीडियो मिटाने की अनुमति देना चाहते हैं?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> वीडियो मिटाया जा रहा है…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> वीडियो मिटाए जा रहे हैं…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="one">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> फ़ोटो मिटाने की अनुमति देना चाहते हैं?</item>
<item quantity="other">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> फ़ोटो मिटाने की अनुमति देना चाहते हैं?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> फ़ोटो मिटाई जा रही है…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> फ़ोटो मिटाई जा रही हैं…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="one">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> आइटम मिटाने की अनुमति देना चाहते हैं?</item>
<item quantity="other">क्या आप <xliff:g id="APP_NAME_1">^1</xliff:g> को <xliff:g id="COUNT">^2</xliff:g> आइटम मिटाने की अनुमति देना चाहते हैं?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> आइटम मिटाया जा रहा है…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> आइटम मिटाए जा रहे हैं…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> मीडिया फ़ाइलों को प्रोसेस नहीं कर सकता"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"मीडिया को प्रोसेस करने की कार्रवाई रद्द की गई"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"मीडिया को प्रोसेस करने में गड़बड़ी हुई"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"मीडिया को प्रोसेस कर लिया गया"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"मीडिया को प्रोसेस करना शुरू किया गया"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"मीडिया को प्रोसेस किया जा रहा है…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"अभी नहीं"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"इंतज़ार करें"</string>
</resources>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 6b4abd9..776b290 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -50,79 +50,167 @@
<item quantity="few">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da izmijeni <xliff:g id="COUNT">^2</xliff:g> audiodatoteke?</item>
<item quantity="other">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da izmijeni <xliff:g id="COUNT">^2</xliff:g> audiodatoteka?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="one">Mijenjanje <xliff:g id="COUNT">^1</xliff:g> audiodatoteke…</item>
+ <item quantity="few">Mijenjanje <xliff:g id="COUNT">^1</xliff:g> audiodatoteke…</item>
+ <item quantity="other">Mijenjanje <xliff:g id="COUNT">^1</xliff:g> audiodatoteka…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="one">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da izmijeni <xliff:g id="COUNT">^2</xliff:g> videozapis?</item>
<item quantity="few">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da izmijeni <xliff:g id="COUNT">^2</xliff:g> videozapisa?</item>
<item quantity="other">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da izmijeni <xliff:g id="COUNT">^2</xliff:g> videozapisa?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="one">Mijenjanje <xliff:g id="COUNT">^1</xliff:g> videozapisa…</item>
+ <item quantity="few">Mijenjanje <xliff:g id="COUNT">^1</xliff:g> videozapisa…</item>
+ <item quantity="other">Mijenjanje <xliff:g id="COUNT">^1</xliff:g> videozapisa…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="one">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da izmijeni <xliff:g id="COUNT">^2</xliff:g> fotografiju?</item>
<item quantity="few">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da izmijeni <xliff:g id="COUNT">^2</xliff:g> fotografije?</item>
<item quantity="other">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da izmijeni <xliff:g id="COUNT">^2</xliff:g> fotografija?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="one">Mijenjanje <xliff:g id="COUNT">^1</xliff:g> fotografije…</item>
+ <item quantity="few">Mijenjanje <xliff:g id="COUNT">^1</xliff:g> fotografije…</item>
+ <item quantity="other">Mijenjanje <xliff:g id="COUNT">^1</xliff:g> fotografija…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="one">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da izmijeni <xliff:g id="COUNT">^2</xliff:g> stavku?</item>
<item quantity="few">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da izmijeni <xliff:g id="COUNT">^2</xliff:g> stavke?</item>
<item quantity="other">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da izmijeni <xliff:g id="COUNT">^2</xliff:g> stavki?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="one">Mijenjanje <xliff:g id="COUNT">^1</xliff:g> stavke…</item>
+ <item quantity="few">Mijenjanje <xliff:g id="COUNT">^1</xliff:g> stavke…</item>
+ <item quantity="other">Mijenjanje <xliff:g id="COUNT">^1</xliff:g> stavki…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="one">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da premjesti <xliff:g id="COUNT">^2</xliff:g> audiodatoteku u otpad?</item>
<item quantity="few">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da premjesti <xliff:g id="COUNT">^2</xliff:g> audiodatoteke u otpad?</item>
<item quantity="other">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da premjesti <xliff:g id="COUNT">^2</xliff:g> audiodatoteka u otpad?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="one">Premještanje <xliff:g id="COUNT">^1</xliff:g> audiodatoteke u otpad…</item>
+ <item quantity="few">Premještanje <xliff:g id="COUNT">^1</xliff:g> audiodatoteke u otpad…</item>
+ <item quantity="other">Premještanje <xliff:g id="COUNT">^1</xliff:g> audiodatoteka u otpad…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="one">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da premjesti <xliff:g id="COUNT">^2</xliff:g> videozapis u otpad?</item>
<item quantity="few">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da premjesti <xliff:g id="COUNT">^2</xliff:g> videozapisa u otpad?</item>
<item quantity="other">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da premjesti <xliff:g id="COUNT">^2</xliff:g> videozapisa u otpad?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="one">Premještanje <xliff:g id="COUNT">^1</xliff:g> videozapisa u otpad…</item>
+ <item quantity="few">Premještanje <xliff:g id="COUNT">^1</xliff:g> videozapisa u otpad…</item>
+ <item quantity="other">Premještanje <xliff:g id="COUNT">^1</xliff:g> videozapisa u otpad…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="one">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da premjesti <xliff:g id="COUNT">^2</xliff:g> fotografiju u otpad?</item>
<item quantity="few">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da premjesti <xliff:g id="COUNT">^2</xliff:g> fotografije u otpad?</item>
<item quantity="other">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da premjesti <xliff:g id="COUNT">^2</xliff:g> fotografija u otpad?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="one">Premještanje <xliff:g id="COUNT">^1</xliff:g> fotografije u otpad…</item>
+ <item quantity="few">Premještanje <xliff:g id="COUNT">^1</xliff:g> fotografije u otpad…</item>
+ <item quantity="other">Premještanje <xliff:g id="COUNT">^1</xliff:g> fotografija u otpad…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="one">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da premjesti <xliff:g id="COUNT">^2</xliff:g> stavku u otpad?</item>
<item quantity="few">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da premjesti <xliff:g id="COUNT">^2</xliff:g> stavke u otpad?</item>
<item quantity="other">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da premjesti <xliff:g id="COUNT">^2</xliff:g> stavki u otpad?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="one">Premještanje <xliff:g id="COUNT">^1</xliff:g> stavke u otpad…</item>
+ <item quantity="few">Premještanje <xliff:g id="COUNT">^1</xliff:g> stavke u otpad…</item>
+ <item quantity="other">Premještanje <xliff:g id="COUNT">^1</xliff:g> stavki u otpad…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="one">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da premjesti <xliff:g id="COUNT">^2</xliff:g> audiodatoteku iz otpada?</item>
<item quantity="few">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da premjesti <xliff:g id="COUNT">^2</xliff:g> audiodatoteke iz otpada?</item>
<item quantity="other">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da premjesti <xliff:g id="COUNT">^2</xliff:g> audiodatoteka iz otpada?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="one">Premještanje <xliff:g id="COUNT">^1</xliff:g> audiodatoteke iz otpada…</item>
+ <item quantity="few">Premještanje <xliff:g id="COUNT">^1</xliff:g> audiodatoteke iz otpada…</item>
+ <item quantity="other">Premještanje <xliff:g id="COUNT">^1</xliff:g> audiodatoteka iz otpada…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="one">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da premjesti <xliff:g id="COUNT">^2</xliff:g> videozapis iz otpada?</item>
<item quantity="few">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da premjesti <xliff:g id="COUNT">^2</xliff:g> videozapisa iz otpada?</item>
<item quantity="other">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da premjesti <xliff:g id="COUNT">^2</xliff:g> videozapisa iz otpada?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="one">Premještanje <xliff:g id="COUNT">^1</xliff:g> videozapisa iz otpada…</item>
+ <item quantity="few">Premještanje <xliff:g id="COUNT">^1</xliff:g> videozapisa iz otpada…</item>
+ <item quantity="other">Premještanje <xliff:g id="COUNT">^1</xliff:g> videozapisa iz otpada…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="one">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da premjesti <xliff:g id="COUNT">^2</xliff:g> fotografiju iz otpada?</item>
<item quantity="few">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da premjesti <xliff:g id="COUNT">^2</xliff:g> fotografije iz otpada?</item>
<item quantity="other">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da premjesti <xliff:g id="COUNT">^2</xliff:g> fotografija iz otpada?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="one">Premještanje <xliff:g id="COUNT">^1</xliff:g> fotografije iz otpada…</item>
+ <item quantity="few">Premještanje <xliff:g id="COUNT">^1</xliff:g> fotografije iz otpada…</item>
+ <item quantity="other">Premještanje <xliff:g id="COUNT">^1</xliff:g> fotografija iz otpada…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="one">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da premjesti <xliff:g id="COUNT">^2</xliff:g> stavku iz otpada?</item>
<item quantity="few">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da premjesti <xliff:g id="COUNT">^2</xliff:g> stavke iz otpada?</item>
<item quantity="other">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da premjesti <xliff:g id="COUNT">^2</xliff:g> stavki iz otpada?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="one">Premještanje <xliff:g id="COUNT">^1</xliff:g> stavke iz otpada…</item>
+ <item quantity="few">Premještanje <xliff:g id="COUNT">^1</xliff:g> stavke iz otpada…</item>
+ <item quantity="other">Premještanje <xliff:g id="COUNT">^1</xliff:g> stavki iz otpada…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="one">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da izbriše <xliff:g id="COUNT">^2</xliff:g> audiodatoteku?</item>
<item quantity="few">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da izbriše <xliff:g id="COUNT">^2</xliff:g> audiodatoteke?</item>
<item quantity="other">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da izbriše <xliff:g id="COUNT">^2</xliff:g> audiodatoteka?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="one">Brisanje <xliff:g id="COUNT">^1</xliff:g> audiodatoteke…</item>
+ <item quantity="few">Brisanje <xliff:g id="COUNT">^1</xliff:g> audiodatoteke…</item>
+ <item quantity="other">Brisanje <xliff:g id="COUNT">^1</xliff:g> audiodatoteka…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="one">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da izbriše <xliff:g id="COUNT">^2</xliff:g> videozapis?</item>
<item quantity="few">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da izbriše <xliff:g id="COUNT">^2</xliff:g> videozapisa?</item>
<item quantity="other">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da izbriše <xliff:g id="COUNT">^2</xliff:g> videozapisa?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="one">Brisanje <xliff:g id="COUNT">^1</xliff:g> videozapisa…</item>
+ <item quantity="few">Brisanje <xliff:g id="COUNT">^1</xliff:g> videozapisa…</item>
+ <item quantity="other">Brisanje <xliff:g id="COUNT">^1</xliff:g> videozapisa…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="one">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da izbriše <xliff:g id="COUNT">^2</xliff:g> fotografiju?</item>
<item quantity="few">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da izbriše <xliff:g id="COUNT">^2</xliff:g> fotografije?</item>
<item quantity="other">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da izbriše <xliff:g id="COUNT">^2</xliff:g> fotografija?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="one">Brisanje <xliff:g id="COUNT">^1</xliff:g> fotografije…</item>
+ <item quantity="few">Brisanje <xliff:g id="COUNT">^1</xliff:g> fotografije…</item>
+ <item quantity="other">Brisanje <xliff:g id="COUNT">^1</xliff:g> fotografija…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="one">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da izbriše <xliff:g id="COUNT">^2</xliff:g> stavku?</item>
<item quantity="few">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da izbriše <xliff:g id="COUNT">^2</xliff:g> stavke?</item>
<item quantity="other">Želite li dopustiti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g> da izbriše <xliff:g id="COUNT">^2</xliff:g> stavki?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="one">Brisanje <xliff:g id="COUNT">^1</xliff:g> stavke…</item>
+ <item quantity="few">Brisanje <xliff:g id="COUNT">^1</xliff:g> stavke…</item>
+ <item quantity="other">Brisanje <xliff:g id="COUNT">^1</xliff:g> stavki…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"Aplikacija <xliff:g id="APP_NAME">%s</xliff:g> ne može obraditi medijske datoteke"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Obrada medijskih sadržaja otkazana"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Pogreška prilikom obrade medijskih sadržaja"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Obrada medijskih sadržaja uspješno je dovršena"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Započela je obrada medijskih sadržaja"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Obrada medijskih sadržaja…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Odustani"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Pričekaj"</string>
</resources>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 1e39499..e3ea512 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">Engedélyezi a(z) <xliff:g id="APP_NAME_1">^1</xliff:g> számára <xliff:g id="COUNT">^2</xliff:g> hangfájl módosítását?</item>
<item quantity="one">Engedélyezi a(z) <xliff:g id="APP_NAME_0">^1</xliff:g> számára ennek a hangfájlnak a módosítását?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> audiofájl módosítása folyamatban van…</item>
+ <item quantity="one">Az audiofájl módosítása folyamatban van…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">Engedélyezi a(z) <xliff:g id="APP_NAME_1">^1</xliff:g> számára <xliff:g id="COUNT">^2</xliff:g> videó módosítását?</item>
<item quantity="one">Engedélyezi a(z) <xliff:g id="APP_NAME_0">^1</xliff:g> számára ennek a videónak a módosítását?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> videó módosítása folyamatban van…</item>
+ <item quantity="one">A videó módosítása folyamatban van…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">Engedélyezi a(z) <xliff:g id="APP_NAME_1">^1</xliff:g> számára <xliff:g id="COUNT">^2</xliff:g> fotó módosítását?</item>
<item quantity="one">Engedélyezi a(z) <xliff:g id="APP_NAME_0">^1</xliff:g> számára ennek a fotónak a módosítását?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> fotó módosítása folyamatban van…</item>
+ <item quantity="one">A fotó módosítása folyamatban van…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">Engedélyezi a(z) <xliff:g id="APP_NAME_1">^1</xliff:g> számára <xliff:g id="COUNT">^2</xliff:g> elem módosítását?</item>
<item quantity="one">Engedélyezi a(z) <xliff:g id="APP_NAME_0">^1</xliff:g> számára ennek az elemnek a módosítását?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> elem módosítása folyamatban van…</item>
+ <item quantity="one">Az elem módosítása folyamatban van…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">Engedélyezi a(z) <xliff:g id="APP_NAME_1">^1</xliff:g> számára <xliff:g id="COUNT">^2</xliff:g> hangfájlnak a kukába helyezését?</item>
<item quantity="one">Engedélyezi a(z) <xliff:g id="APP_NAME_0">^1</xliff:g> számára ennek a hangfájlnak a kukába helyezését?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> audiofájl áthelyezése a kukába…</item>
+ <item quantity="one">Az audiofájl áthelyezése a kukába…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">Engedélyezi a(z) <xliff:g id="APP_NAME_1">^1</xliff:g> számára <xliff:g id="COUNT">^2</xliff:g> videónak a kukába helyezését?</item>
<item quantity="one">Engedélyezi a(z) <xliff:g id="APP_NAME_0">^1</xliff:g> számára ennek a videónak a kukába helyezését?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> videó áthelyezése a kukába…</item>
+ <item quantity="one">Videó áthelyezése a kukába…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">Engedélyezi a(z) <xliff:g id="APP_NAME_1">^1</xliff:g> számára <xliff:g id="COUNT">^2</xliff:g> fotónak a kukába helyezését?</item>
<item quantity="one">Engedélyezi a(z) <xliff:g id="APP_NAME_0">^1</xliff:g> számára ennek a fotónak a kukába helyezését?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> fotó áthelyezése a kukába…</item>
+ <item quantity="one">Fotó áthelyezése a kukába…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">Engedélyezi a(z) <xliff:g id="APP_NAME_1">^1</xliff:g> számára <xliff:g id="COUNT">^2</xliff:g> elemnek a kukába helyezését?</item>
<item quantity="one">Engedélyezi a(z) <xliff:g id="APP_NAME_0">^1</xliff:g> számára ennek az elemnek a kukába helyezését?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> elem áthelyezése a kukába…</item>
+ <item quantity="one">Az elem áthelyezése a kukába…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">Engedélyezi a(z) <xliff:g id="APP_NAME_1">^1</xliff:g> számára <xliff:g id="COUNT">^2</xliff:g> hangfájlnak a kukából való visszaállítását?</item>
<item quantity="one">Engedélyezi a(z) <xliff:g id="APP_NAME_0">^1</xliff:g> számára ennek a hangfájlnak a kukából való visszaállítását?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> audiofájl visszaállítása a kukából…</item>
+ <item quantity="one">Audiofájl visszaállítása a kukából…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">Engedélyezi a(z) <xliff:g id="APP_NAME_1">^1</xliff:g> számára <xliff:g id="COUNT">^2</xliff:g> videónak a kukából való visszaállítását?</item>
<item quantity="one">Engedélyezi a(z) <xliff:g id="APP_NAME_0">^1</xliff:g> számára ennek a videónak a kukából való visszaállítását?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> videó visszaállítása a kukából…</item>
+ <item quantity="one">Videó visszaállítása a kukából…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">Engedélyezi a(z) <xliff:g id="APP_NAME_1">^1</xliff:g> számára <xliff:g id="COUNT">^2</xliff:g> fotónak a kukából való visszaállítását?</item>
<item quantity="one">Engedélyezi a(z) <xliff:g id="APP_NAME_0">^1</xliff:g> számára ennek a fotónak a kukából való visszaállítását?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> fotó visszaállítása a kukából…</item>
+ <item quantity="one">Fotó visszaállítása a kukából…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">Engedélyezi a(z) <xliff:g id="APP_NAME_1">^1</xliff:g> számára <xliff:g id="COUNT">^2</xliff:g> elemnek a kukából való visszaállítását?</item>
<item quantity="one">Engedélyezi a(z) <xliff:g id="APP_NAME_0">^1</xliff:g> számára ennek az elemnek a kukából való visszaállítását?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> elem visszaállítása a kukából…</item>
+ <item quantity="one">Elem visszaállítása a kukából…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">Engedélyezi a(z) <xliff:g id="APP_NAME_1">^1</xliff:g> számára <xliff:g id="COUNT">^2</xliff:g> audiofájl törlését?</item>
<item quantity="one">Engedélyezi a(z) <xliff:g id="APP_NAME_0">^1</xliff:g> számára ennek az audiofájlnak a törlését?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> audiofájl törlése folyamatban van…</item>
+ <item quantity="one">Az audiofájl törlése folyamatban van…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">Engedélyezi a(z) <xliff:g id="APP_NAME_1">^1</xliff:g> számára <xliff:g id="COUNT">^2</xliff:g> videó törlését?</item>
<item quantity="one">Engedélyezi a(z) <xliff:g id="APP_NAME_0">^1</xliff:g> számára ennek a videónak a törlését?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> videó törlése folyamatban van…</item>
+ <item quantity="one">A videó törlése folyamatban van…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">Engedélyezi a(z) <xliff:g id="APP_NAME_1">^1</xliff:g> számára <xliff:g id="COUNT">^2</xliff:g> fotó törlését?</item>
<item quantity="one">Engedélyezi a(z) <xliff:g id="APP_NAME_0">^1</xliff:g> számára ennek a fotónak a törlését?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> fotó törlése folyamatban van…</item>
+ <item quantity="one">A fotó törlése folyamatban van…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">Engedélyezi a(z) <xliff:g id="APP_NAME_1">^1</xliff:g> számára <xliff:g id="COUNT">^2</xliff:g> elem törlését?</item>
<item quantity="one">Engedélyezi a(z) <xliff:g id="APP_NAME_0">^1</xliff:g> számára ennek az elemnek a törlését?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> elem törlése folyamatban van…</item>
+ <item quantity="one">Az elem törlése folyamatban van…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"A(z) <xliff:g id="APP_NAME">%s</xliff:g> nem tudja feldolgozni a médiafájlokat"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Mediatartalom feldolgozása megszakítva"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Médiatartalom-feldolgozási hiba"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Médiatartalom feldolgozása sikeres"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Médiatartalom feldolgozása megkezdődött"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Médiatartalom feldolgozása…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Mégse"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Várakozás"</string>
</resources>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 862e27a..095e238 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -47,64 +47,136 @@
<item quantity="one">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին վերականգնել <xliff:g id="COUNT">^2</xliff:g> աուդիո ֆայլ աղբարկղից</item>
<item quantity="other">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին վերականգնել <xliff:g id="COUNT">^2</xliff:g> աուդիո ֆայլ աղբարկղից</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> աուդիո ֆայլ փոփոխվում է…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> աուդիո ֆայլ փոփոխվում է…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="one">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին փոփոխել <xliff:g id="COUNT">^2</xliff:g> տեսանյութ</item>
<item quantity="other">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին փոփոխել <xliff:g id="COUNT">^2</xliff:g> տեսանյութ</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> տեսանյութ փոփոխվում է…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> տեսանյութ փոփոխվում է…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="one">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին փոփոխել <xliff:g id="COUNT">^2</xliff:g> լուսանկար</item>
<item quantity="other">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին փոփոխել <xliff:g id="COUNT">^2</xliff:g> լուսանկար</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> լուսանկար փոփոխվում է…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> լուսանկար փոփոխվում է…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="one">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին փոփոխել <xliff:g id="COUNT">^2</xliff:g> տարր</item>
<item quantity="other">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին փոփոխել <xliff:g id="COUNT">^2</xliff:g> տարր</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> տարր փոփոխվում է…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> տարր փոփոխվում է…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="one">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին տեղափոխել <xliff:g id="COUNT">^2</xliff:g> աուդիո ֆայլ աղբարկղ</item>
<item quantity="other">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին տեղափոխել <xliff:g id="COUNT">^2</xliff:g> աուդիո ֆայլ աղբարկղ</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> աուդիո ֆայլ տեղափոխվում է աղբարկղ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> աուդիո ֆայլ տեղափոխվում է աղբարկղ…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="one">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին տեղափոխել <xliff:g id="COUNT">^2</xliff:g> տեսանյութ աղբարկղ</item>
<item quantity="other">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին տեղափոխել <xliff:g id="COUNT">^2</xliff:g> տեսանյութ աղբարկղ</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> տեսանյութ տեղափոխվում է աղբարկղ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> տեսանյութ տեղափոխվում է աղբարկղ…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="one">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին տեղափոխել <xliff:g id="COUNT">^2</xliff:g> լուսանկար աղբարկղ</item>
<item quantity="other">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին տեղափոխել <xliff:g id="COUNT">^2</xliff:g> լուսանկար աղբարկղ</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> լուսանկար տեղափոխվում է աղբարկղ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> լուսանկար տեղափոխվում է աղբարկղ…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="one">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին տեղափոխել <xliff:g id="COUNT">^2</xliff:g> տարր աղբարկղ</item>
<item quantity="other">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին տեղափոխել <xliff:g id="COUNT">^2</xliff:g> տարր աղբարկղ</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> տարր տեղափոխվում է աղբարկղ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> տարր տեղափոխվում է աղբարկղ…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="one">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին վերականգնել<xliff:g id="COUNT">^2</xliff:g> աուդիո ֆայլ աղբարկղից</item>
<item quantity="other">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին վերականգնել<xliff:g id="COUNT">^2</xliff:g> աուդիո ֆայլ աղբարկղից</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> աուդիո ֆայլ վերականգնվում է աղբարկղից…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> աուդիո ֆայլ վերականգնվում է աղբարկղից…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="one">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին վերականգնել <xliff:g id="COUNT">^2</xliff:g> տեսանյութ աղբարկղից</item>
<item quantity="other">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին վերականգնել <xliff:g id="COUNT">^2</xliff:g> տեսանյութ աղբարկղից</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> տեսանյութ վերականգնվում է աղբարկղից…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> տեսանյութ վերականգնվում է աղբարկղից…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="one">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին վերականգնել <xliff:g id="COUNT">^2</xliff:g> լուսանկար աղբարկղից</item>
<item quantity="other">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին վերականգնել <xliff:g id="COUNT">^2</xliff:g> լուսանկար աղբարկղից</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> լուսանկար վերականգնվում է աղբարկղից…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> լուսանկար վերականգնվում է աղբարկղից…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="one">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին վերականգնել <xliff:g id="COUNT">^2</xliff:g> տարր աղբարկղից</item>
<item quantity="other">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին վերականգնել <xliff:g id="COUNT">^2</xliff:g> տարր աղբարկղից</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> տարր վերականգնվում է աղբարկղից…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> տարր վերականգնվում է աղբարկղից…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="one">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին ջնջել <xliff:g id="COUNT">^2</xliff:g> աուդիո ֆայլ</item>
<item quantity="other">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին ջնջել <xliff:g id="COUNT">^2</xliff:g> աուդիո ֆայլ</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> աուդիո ֆայլ ջնջվում է…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> աուդիո ֆայլ ջնջվում է…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="one">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին ջնջել <xliff:g id="COUNT">^2</xliff:g> տեսանյութ</item>
<item quantity="other">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին ջնջել <xliff:g id="COUNT">^2</xliff:g> տեսանյութ</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> տեսանյութ ջնջվում է…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> տեսանյութ ջնջվում է…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="one">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին ջնջել <xliff:g id="COUNT">^2</xliff:g> լուսանկար</item>
<item quantity="other">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին ջնջել <xliff:g id="COUNT">^2</xliff:g> լուսանկար</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> լուսանկար ջնջվում է…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> լուսանկար ջնջվում է…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="one">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին ջնջել <xliff:g id="COUNT">^2</xliff:g> տարր</item>
<item quantity="other">Թույլատրե՞լ <xliff:g id="APP_NAME_1">^1</xliff:g> հավելվածին ջնջել <xliff:g id="COUNT">^2</xliff:g> տարր</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> տարր ջնջվում է…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> տարր ջնջվում է…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> հավելվածը չի կարող մեդիաֆայլեր մշակել"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Մեդիաֆայլի մշակումը չեղարկվել է"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Մեդիաֆայլի մշակման սխալ"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Մեդիաֆայլի մշակումն ավարտված է"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Մեդիաֆայլի մշակումը սկսված է"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Մեդիաֆայլը մշակվում է…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Չեղարկել"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Սպասել"</string>
</resources>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 42406d7..3987c55 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">Izinkan <xliff:g id="APP_NAME_1">^1</xliff:g> untuk mengubah <xliff:g id="COUNT">^2</xliff:g> file audio?</item>
<item quantity="one">Izinkan <xliff:g id="APP_NAME_0">^1</xliff:g> untuk mengubah file audio ini?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other">Mengubah <xliff:g id="COUNT">^1</xliff:g> file audio …</item>
+ <item quantity="one">Mengubah file audio …</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">Izinkan <xliff:g id="APP_NAME_1">^1</xliff:g> untuk mengubah <xliff:g id="COUNT">^2</xliff:g> video?</item>
<item quantity="one">Izinkan <xliff:g id="APP_NAME_0">^1</xliff:g> untuk mengubah video ini?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other">Mengubah <xliff:g id="COUNT">^1</xliff:g> video …</item>
+ <item quantity="one">Mengubah video …</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">Izinkan <xliff:g id="APP_NAME_1">^1</xliff:g> untuk mengubah <xliff:g id="COUNT">^2</xliff:g> foto?</item>
<item quantity="one">Izinkan <xliff:g id="APP_NAME_0">^1</xliff:g> untuk mengubah foto ini?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other">Mengubah <xliff:g id="COUNT">^1</xliff:g> foto …</item>
+ <item quantity="one">Mengubah foto …</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">Izinkan <xliff:g id="APP_NAME_1">^1</xliff:g> untuk mengubah <xliff:g id="COUNT">^2</xliff:g> item?</item>
<item quantity="one">Izinkan <xliff:g id="APP_NAME_0">^1</xliff:g> untuk mengubah item ini?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other">Mengubah <xliff:g id="COUNT">^1</xliff:g> item …</item>
+ <item quantity="one">Mengubah item …</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">Izinkan <xliff:g id="APP_NAME_1">^1</xliff:g> untuk memindahkan <xliff:g id="COUNT">^2</xliff:g> file audio ke sampah?</item>
<item quantity="one">Izinkan <xliff:g id="APP_NAME_0">^1</xliff:g> untuk memindahkan file audio ini ke sampah?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other">Memindahkan <xliff:g id="COUNT">^1</xliff:g> file audio ke sampah …</item>
+ <item quantity="one">Memindahkan file audio ke sampah …</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">Izinkan <xliff:g id="APP_NAME_1">^1</xliff:g> untuk memindahkan <xliff:g id="COUNT">^2</xliff:g> video ke sampah?</item>
<item quantity="one">Izinkan <xliff:g id="APP_NAME_0">^1</xliff:g> untuk memindahkan video ini ke sampah?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other">Memindahkan <xliff:g id="COUNT">^1</xliff:g> video ke sampah …</item>
+ <item quantity="one">Memindahkan video ke sampah …</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">Izinkan <xliff:g id="APP_NAME_1">^1</xliff:g> untuk memindahkan <xliff:g id="COUNT">^2</xliff:g> foto ke sampah?</item>
<item quantity="one">Izinkan <xliff:g id="APP_NAME_0">^1</xliff:g> untuk memindahkan foto ini ke sampah?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other">Memindahkan <xliff:g id="COUNT">^1</xliff:g> foto ke sampah …</item>
+ <item quantity="one">Memindahkan foto ke sampah …</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">Izinkan <xliff:g id="APP_NAME_1">^1</xliff:g> untuk memindahkan <xliff:g id="COUNT">^2</xliff:g> item ke sampah?</item>
<item quantity="one">Izinkan <xliff:g id="APP_NAME_0">^1</xliff:g> untuk memindahkan item ini ke sampah?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other">Memindahkan <xliff:g id="COUNT">^1</xliff:g> item ke sampah …</item>
+ <item quantity="one">Memindahkan item ke sampah …</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">Izinkan <xliff:g id="APP_NAME_1">^1</xliff:g> untuk mengeluarkan <xliff:g id="COUNT">^2</xliff:g> file audio dari sampah?</item>
<item quantity="one">Izinkan <xliff:g id="APP_NAME_0">^1</xliff:g> untuk mengeluarkan file audio ini dari sampah?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other">Memindahkan <xliff:g id="COUNT">^1</xliff:g> file audio dari sampah …</item>
+ <item quantity="one">Memindahkan file audio dari sampah …</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">Izinkan <xliff:g id="APP_NAME_1">^1</xliff:g> untuk mengeluarkan <xliff:g id="COUNT">^2</xliff:g> video dari sampah?</item>
<item quantity="one">Izinkan <xliff:g id="APP_NAME_0">^1</xliff:g> untuk mengeluarkan video ini dari sampah?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other">Memindahkan <xliff:g id="COUNT">^1</xliff:g> video dari sampah …</item>
+ <item quantity="one">Memindahkan video dari sampah …</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">Izinkan <xliff:g id="APP_NAME_1">^1</xliff:g> untuk mengeluarkan <xliff:g id="COUNT">^2</xliff:g> foto dari sampah?</item>
<item quantity="one">Izinkan <xliff:g id="APP_NAME_0">^1</xliff:g> untuk mengeluarkan foto ini dari sampah?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other">Memindahkan <xliff:g id="COUNT">^1</xliff:g> foto dari sampah …</item>
+ <item quantity="one">Memindahkan foto dari sampah …</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">Izinkan <xliff:g id="APP_NAME_1">^1</xliff:g> untuk mengeluarkan <xliff:g id="COUNT">^2</xliff:g> item dari sampah?</item>
<item quantity="one">Izinkan <xliff:g id="APP_NAME_0">^1</xliff:g> untuk mengeluarkan item ini dari sampah?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other">Memindahkan <xliff:g id="COUNT">^1</xliff:g> item dari sampah …</item>
+ <item quantity="one">Memindahkan item dari sampah …</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">Izinkan <xliff:g id="APP_NAME_1">^1</xliff:g> untuk menghapus <xliff:g id="COUNT">^2</xliff:g> file audio?</item>
<item quantity="one">Izinkan <xliff:g id="APP_NAME_0">^1</xliff:g> untuk menghapus file audio ini?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other">Menghapus <xliff:g id="COUNT">^1</xliff:g> file audio …</item>
+ <item quantity="one">Menghapus file audio …</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">Izinkan <xliff:g id="APP_NAME_1">^1</xliff:g> untuk menghapus <xliff:g id="COUNT">^2</xliff:g> video?</item>
<item quantity="one">Izinkan <xliff:g id="APP_NAME_0">^1</xliff:g> untuk menghapus video ini?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other">Menghapus <xliff:g id="COUNT">^1</xliff:g> video …</item>
+ <item quantity="one">Menghapus video …</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">Izinkan <xliff:g id="APP_NAME_1">^1</xliff:g> untuk menghapus <xliff:g id="COUNT">^2</xliff:g> foto?</item>
<item quantity="one">Izinkan <xliff:g id="APP_NAME_0">^1</xliff:g> untuk menghapus foto ini?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other">Menghapus <xliff:g id="COUNT">^1</xliff:g> foto …</item>
+ <item quantity="one">Menghapus foto …</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">Izinkan <xliff:g id="APP_NAME_1">^1</xliff:g> untuk menghapus <xliff:g id="COUNT">^2</xliff:g> item?</item>
<item quantity="one">Izinkan <xliff:g id="APP_NAME_0">^1</xliff:g> untuk menghapus item ini?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other">Menghapus <xliff:g id="COUNT">^1</xliff:g> item …</item>
+ <item quantity="one">Menghapus item …</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> tidak dapat memproses file media"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Pemrosesan media dibatalkan"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Pemrosesan media mengalami error"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Pemrosesan media berhasil"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Pemrosesan media dimulai"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Memproses media…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Batal"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Tunggu"</string>
</resources>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index fb7daa3..cf0d7c8 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -47,64 +47,136 @@
<item quantity="one">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að breyta <xliff:g id="COUNT">^2</xliff:g> hljóðskrá?</item>
<item quantity="other">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að breyta <xliff:g id="COUNT">^2</xliff:g> hljóðskrám?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="one">Breytir <xliff:g id="COUNT">^1</xliff:g> hljóðskrá…</item>
+ <item quantity="other">Breytir <xliff:g id="COUNT">^1</xliff:g> hljóðskrám…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="one">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að breyta <xliff:g id="COUNT">^2</xliff:g> myndskeiði?</item>
<item quantity="other">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að breyta <xliff:g id="COUNT">^2</xliff:g> myndskeiðum?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="one">Breytir <xliff:g id="COUNT">^1</xliff:g> myndskeiði…</item>
+ <item quantity="other">Breytir <xliff:g id="COUNT">^1</xliff:g> myndskeiðum…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="one">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að breyta <xliff:g id="COUNT">^2</xliff:g> mynd?</item>
<item quantity="other">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að breyta <xliff:g id="COUNT">^2</xliff:g> myndum?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="one">Breytir <xliff:g id="COUNT">^1</xliff:g> mynd…</item>
+ <item quantity="other">Breytir <xliff:g id="COUNT">^1</xliff:g> myndum…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="one">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að breyta <xliff:g id="COUNT">^2</xliff:g> atriði?</item>
<item quantity="other">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að breyta <xliff:g id="COUNT">^2</xliff:g> atriðum?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="one">Breytir <xliff:g id="COUNT">^1</xliff:g> atriði…</item>
+ <item quantity="other">Breytir <xliff:g id="COUNT">^1</xliff:g> atriðum…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="one">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að færa <xliff:g id="COUNT">^2</xliff:g> hljóðskrá í ruslið?</item>
<item quantity="other">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að færa <xliff:g id="COUNT">^2</xliff:g> hljóðskrár í ruslið?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="one">Færir <xliff:g id="COUNT">^1</xliff:g> hljóðskrá í ruslið…</item>
+ <item quantity="other">Færir <xliff:g id="COUNT">^1</xliff:g> hljóðskrár í ruslið…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="one">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að færa <xliff:g id="COUNT">^2</xliff:g> myndskeið í ruslið?</item>
<item quantity="other">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að færa <xliff:g id="COUNT">^2</xliff:g> myndskeið í ruslið?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="one">Færir <xliff:g id="COUNT">^1</xliff:g> myndskeið í ruslið…</item>
+ <item quantity="other">Færir <xliff:g id="COUNT">^1</xliff:g> myndskeið í ruslið…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="one">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að færa <xliff:g id="COUNT">^2</xliff:g> mynd í ruslið?</item>
<item quantity="other">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að færa <xliff:g id="COUNT">^2</xliff:g> myndir í ruslið?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="one">Færir <xliff:g id="COUNT">^1</xliff:g> mynd í ruslið…</item>
+ <item quantity="other">Færir <xliff:g id="COUNT">^1</xliff:g> myndir í ruslið…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="one">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að færa <xliff:g id="COUNT">^2</xliff:g> atriði í ruslið?</item>
<item quantity="other">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að færa <xliff:g id="COUNT">^2</xliff:g> atriði í ruslið?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="one">Færir <xliff:g id="COUNT">^1</xliff:g> atriði í ruslið…</item>
+ <item quantity="other">Færir <xliff:g id="COUNT">^1</xliff:g> atriði í ruslið…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="one">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að færa <xliff:g id="COUNT">^2</xliff:g> hljóðskrá úr ruslinu?</item>
<item quantity="other">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að færa <xliff:g id="COUNT">^2</xliff:g> hljóðskrár úr ruslinu?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="one">Færir <xliff:g id="COUNT">^1</xliff:g> hljóðskrá úr ruslinu…</item>
+ <item quantity="other">Færir <xliff:g id="COUNT">^1</xliff:g> hljóðskrár úr ruslinu…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="one">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að færa <xliff:g id="COUNT">^2</xliff:g> myndskeið úr ruslinu?</item>
<item quantity="other">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að færa <xliff:g id="COUNT">^2</xliff:g> myndskeið úr ruslinu?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="one">Færir <xliff:g id="COUNT">^1</xliff:g> myndskeið úr ruslinu…</item>
+ <item quantity="other">Færir <xliff:g id="COUNT">^1</xliff:g> myndskeið úr ruslinu…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="one">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að færa <xliff:g id="COUNT">^2</xliff:g> mynd úr ruslinu?</item>
<item quantity="other">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að færa <xliff:g id="COUNT">^2</xliff:g> myndir úr ruslinu?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="one">Færir <xliff:g id="COUNT">^1</xliff:g> mynd úr ruslinu…</item>
+ <item quantity="other">Færir <xliff:g id="COUNT">^1</xliff:g> myndir úr ruslinu…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="one">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að færa <xliff:g id="COUNT">^2</xliff:g> atriði úr ruslinu?</item>
<item quantity="other">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að færa <xliff:g id="COUNT">^2</xliff:g> atriði úr ruslinu?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="one">Færir <xliff:g id="COUNT">^1</xliff:g> atriði úr ruslinu…</item>
+ <item quantity="other">Færir <xliff:g id="COUNT">^1</xliff:g> atriði úr ruslinu…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="one">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að eyða <xliff:g id="COUNT">^2</xliff:g> hljóðskrá?</item>
<item quantity="other">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að eyða <xliff:g id="COUNT">^2</xliff:g> hljóðskrám?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="one">Eyðir <xliff:g id="COUNT">^1</xliff:g> hljóðskrá…</item>
+ <item quantity="other">Eyðir <xliff:g id="COUNT">^1</xliff:g> hljóðskrám…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="one">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að eyða <xliff:g id="COUNT">^2</xliff:g> myndskeiði?</item>
<item quantity="other">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að eyða <xliff:g id="COUNT">^2</xliff:g> myndskeiðum?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="one">Eyðir <xliff:g id="COUNT">^1</xliff:g> myndskeiði…</item>
+ <item quantity="other">Eyðir <xliff:g id="COUNT">^1</xliff:g> myndskeiðum…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="one">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að eyða <xliff:g id="COUNT">^2</xliff:g> mynd?</item>
<item quantity="other">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að eyða <xliff:g id="COUNT">^2</xliff:g> myndum?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="one">Eyðir <xliff:g id="COUNT">^1</xliff:g> mynd…</item>
+ <item quantity="other">Eyðir <xliff:g id="COUNT">^1</xliff:g> myndum…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="one">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að eyða <xliff:g id="COUNT">^2</xliff:g> atriði?</item>
<item quantity="other">Leyfa <xliff:g id="APP_NAME_1">^1</xliff:g> að eyða <xliff:g id="COUNT">^2</xliff:g> atriðum?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="one">Eyðir <xliff:g id="COUNT">^1</xliff:g> atriði…</item>
+ <item quantity="other">Eyðir <xliff:g id="COUNT">^1</xliff:g> atriðum…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> getur ekki unnið úr efnisskrám"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Hætt við úrvinnslu efnis"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Villa við úrvinnslu efnis"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Úrvinnsla efnis tókst"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Úrvinnsla efnis hafin"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Vinnur úr efni…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Hætta við"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Bíða"</string>
</resources>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 9b5d598..7906977 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">Consentire all\'app <xliff:g id="APP_NAME_1">^1</xliff:g> di modificare <xliff:g id="COUNT">^2</xliff:g> file audio?</item>
<item quantity="one">Consentire all\'app <xliff:g id="APP_NAME_0">^1</xliff:g> di modificare questo file audio?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other">Modifica di <xliff:g id="COUNT">^1</xliff:g> file audio in corso…</item>
+ <item quantity="one">Modifica del file audio in corso…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">Consentire all\'app <xliff:g id="APP_NAME_1">^1</xliff:g> di modificare <xliff:g id="COUNT">^2</xliff:g> video?</item>
<item quantity="one">Consentire all\'app <xliff:g id="APP_NAME_0">^1</xliff:g> di modificare questo video?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other">Modifica di <xliff:g id="COUNT">^1</xliff:g> video in corso…</item>
+ <item quantity="one">Modifica del video in corso…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">Consentire all\'app <xliff:g id="APP_NAME_1">^1</xliff:g> di modificare <xliff:g id="COUNT">^2</xliff:g> foto?</item>
<item quantity="one">Consentire all\'app <xliff:g id="APP_NAME_0">^1</xliff:g> di modificare questa foto?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other">Modifica di <xliff:g id="COUNT">^1</xliff:g> foto in corso…</item>
+ <item quantity="one">Modifica della foto in corso…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">Consentire all\'app <xliff:g id="APP_NAME_1">^1</xliff:g> di modificare <xliff:g id="COUNT">^2</xliff:g> elementi?</item>
<item quantity="one">Consentire all\'app <xliff:g id="APP_NAME_0">^1</xliff:g> di modificare questo elemento?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other">Modifica di <xliff:g id="COUNT">^1</xliff:g> elementi in corso…</item>
+ <item quantity="one">Modifica dell\'elemento in corso…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">Consentire all\'app <xliff:g id="APP_NAME_1">^1</xliff:g> di spostare <xliff:g id="COUNT">^2</xliff:g> file audio nel cestino?</item>
<item quantity="one">Consentire all\'app <xliff:g id="APP_NAME_0">^1</xliff:g> di spostare questo file audio nel cestino?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other">Spostamento di <xliff:g id="COUNT">^1</xliff:g> file audio nel cestino in corso…</item>
+ <item quantity="one">Spostamento del file audio nel cestino in corso…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">Consentire all\'app <xliff:g id="APP_NAME_1">^1</xliff:g> di spostare <xliff:g id="COUNT">^2</xliff:g> video nel cestino?</item>
<item quantity="one">Consentire all\'app <xliff:g id="APP_NAME_0">^1</xliff:g> di spostare questo video nel cestino?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other">Spostamento di <xliff:g id="COUNT">^1</xliff:g> video nel cestino in corso…</item>
+ <item quantity="one">Spostamento del video nel cestino in corso…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">Consentire all\'app <xliff:g id="APP_NAME_1">^1</xliff:g> di spostare <xliff:g id="COUNT">^2</xliff:g> foto nel cestino?</item>
<item quantity="one">Consentire all\'app <xliff:g id="APP_NAME_0">^1</xliff:g> di spostare questa foto nel cestino?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other">Spostamento di <xliff:g id="COUNT">^1</xliff:g> foto nel cestino in corso…</item>
+ <item quantity="one">Spostamento della foto nel cestino in corso…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">Consentire all\'app <xliff:g id="APP_NAME_1">^1</xliff:g> di spostare <xliff:g id="COUNT">^2</xliff:g> elementi nel cestino?</item>
<item quantity="one">Consentire all\'app <xliff:g id="APP_NAME_0">^1</xliff:g> di spostare questo elemento nel cestino?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other">Spostamento di <xliff:g id="COUNT">^1</xliff:g> elementi nel cestino in corso…</item>
+ <item quantity="one">Spostamento dell\'elemento nel cestino in corso…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">Consentire all\'app <xliff:g id="APP_NAME_1">^1</xliff:g> di spostare <xliff:g id="COUNT">^2</xliff:g> file audio fuori dal cestino?</item>
<item quantity="one">Consentire all\'app <xliff:g id="APP_NAME_0">^1</xliff:g> di spostare questo file audio fuori dal cestino?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other">Spostamento di <xliff:g id="COUNT">^1</xliff:g> file audio fuori dal cestino in corso…</item>
+ <item quantity="one">Spostamento del file audio fuori dal cestino in corso…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">Consentire all\'app <xliff:g id="APP_NAME_1">^1</xliff:g> di spostare <xliff:g id="COUNT">^2</xliff:g> video fuori dal cestino?</item>
<item quantity="one">Consentire all\'app <xliff:g id="APP_NAME_0">^1</xliff:g> di spostare questo video fuori dal cestino?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other">Spostamento di <xliff:g id="COUNT">^1</xliff:g> video fuori dal cestino in corso…</item>
+ <item quantity="one">Spostamento del video fuori dal cestino in corso…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">Consentire all\'app <xliff:g id="APP_NAME_1">^1</xliff:g> di spostare <xliff:g id="COUNT">^2</xliff:g> foto fuori dal cestino?</item>
<item quantity="one">Consentire all\'app <xliff:g id="APP_NAME_0">^1</xliff:g> di spostare questa foto fuori dal dispositivo?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other">Spostamento di <xliff:g id="COUNT">^1</xliff:g> foto fuori dal cestino in corso…</item>
+ <item quantity="one">Spostamento della foto fuori dal cestino in corso…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">Consentire all\'app <xliff:g id="APP_NAME_1">^1</xliff:g> di spostare <xliff:g id="COUNT">^2</xliff:g> elementi fuori dal cestino?</item>
<item quantity="one">Consentire all\'app <xliff:g id="APP_NAME_0">^1</xliff:g> di spostare questo elemento fuori dal cestino?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other">Spostamento di <xliff:g id="COUNT">^1</xliff:g> elementi fuori dal cestino in corso…</item>
+ <item quantity="one">Spostamento dell\'elemento fuori dal cestino in corso…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">Consentire all\'app <xliff:g id="APP_NAME_1">^1</xliff:g> di eliminare <xliff:g id="COUNT">^2</xliff:g> file audio?</item>
<item quantity="one">Consentire all\'app <xliff:g id="APP_NAME_0">^1</xliff:g> di eliminare questo file audio?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other">Eliminazione di <xliff:g id="COUNT">^1</xliff:g> file audio in corso…</item>
+ <item quantity="one">Eliminazione del file audio in corso…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">Consentire all\'app <xliff:g id="APP_NAME_1">^1</xliff:g> di eliminare <xliff:g id="COUNT">^2</xliff:g> video?</item>
<item quantity="one">Consentire all\'app <xliff:g id="APP_NAME_0">^1</xliff:g> di eliminare questo video?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other">Eliminazione di <xliff:g id="COUNT">^1</xliff:g> video in corso…</item>
+ <item quantity="one">Eliminazione del video in corso…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">Consentire all\'app <xliff:g id="APP_NAME_1">^1</xliff:g> di eliminare <xliff:g id="COUNT">^2</xliff:g> foto?</item>
<item quantity="one">Consentire all\'app <xliff:g id="APP_NAME_0">^1</xliff:g> di eliminare questa foto?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other">Eliminazione di <xliff:g id="COUNT">^1</xliff:g> foto in corso…</item>
+ <item quantity="one">Eliminazione della foto in corso…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">Consentire all\'app <xliff:g id="APP_NAME_1">^1</xliff:g> di eliminare <xliff:g id="COUNT">^2</xliff:g> elementi?</item>
<item quantity="one">Consentire all\'app <xliff:g id="APP_NAME_0">^1</xliff:g> di eliminare questo elemento?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other">Eliminazione di <xliff:g id="COUNT">^1</xliff:g> elementi in corso…</item>
+ <item quantity="one">Eliminazione dell\'elemento in corso…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> non può elaborare file multimediali"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Elaborazione dei contenuti multimediali annullata"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Errore nell\'elaborazione dei contenuti multimediali"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Elaborazione dei contenuti multimediali riuscita"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Elaborazione dei contenuti multimediali avviata"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Elaborazione dei contenuti multimediali in corso…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Annulla"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Attendi"</string>
</resources>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index e7011df..4552372 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -53,94 +53,198 @@
<item quantity="other">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> לשנות <xliff:g id="COUNT">^2</xliff:g> קובצי אודיו?</item>
<item quantity="one">לאפשר לאפליקציה <xliff:g id="APP_NAME_0">^1</xliff:g> לשנות את קובץ האודיו הזה?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="two">מתבצע שינוי ב-<xliff:g id="COUNT">^1</xliff:g> קובצי אודיו…</item>
+ <item quantity="many">מתבצע שינוי ב-<xliff:g id="COUNT">^1</xliff:g> קובצי אודיו…</item>
+ <item quantity="other">מתבצע שינוי ב-<xliff:g id="COUNT">^1</xliff:g> קובצי אודיו…</item>
+ <item quantity="one">מתבצע שינוי בקובץ אודיו אחד…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="two">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> לשנות <xliff:g id="COUNT">^2</xliff:g> סרטונים?</item>
<item quantity="many">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> לשנות <xliff:g id="COUNT">^2</xliff:g> סרטונים?</item>
<item quantity="other">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> לשנות <xliff:g id="COUNT">^2</xliff:g> סרטונים?</item>
<item quantity="one">לאפשר לאפליקציה <xliff:g id="APP_NAME_0">^1</xliff:g> לשנות את הסרטון הזה?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="two">מתבצע שינוי ב-<xliff:g id="COUNT">^1</xliff:g> סרטונים…</item>
+ <item quantity="many">מתבצע שינוי ב-<xliff:g id="COUNT">^1</xliff:g> סרטונים…</item>
+ <item quantity="other">מתבצע שינוי ב-<xliff:g id="COUNT">^1</xliff:g> סרטונים…</item>
+ <item quantity="one">מתבצע שינוי בסרטון אחד…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="two">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> לשנות <xliff:g id="COUNT">^2</xliff:g> תמונות?</item>
<item quantity="many">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> לשנות <xliff:g id="COUNT">^2</xliff:g> תמונות?</item>
<item quantity="other">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> לשנות <xliff:g id="COUNT">^2</xliff:g> תמונות?</item>
<item quantity="one">לאפשר לאפליקציה <xliff:g id="APP_NAME_0">^1</xliff:g> לשנות את התמונה הזו?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="two">מתבצע שינוי ב-<xliff:g id="COUNT">^1</xliff:g> תמונות…</item>
+ <item quantity="many">מתבצע שינוי ב-<xliff:g id="COUNT">^1</xliff:g> תמונות…</item>
+ <item quantity="other">מתבצע שינוי ב-<xliff:g id="COUNT">^1</xliff:g> תמונות…</item>
+ <item quantity="one">מתבצע שינוי בתמונה אחת…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="two">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> לשנות <xliff:g id="COUNT">^2</xliff:g> פריטים?</item>
<item quantity="many">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> לשנות <xliff:g id="COUNT">^2</xliff:g> פריטים?</item>
<item quantity="other">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> לשנות <xliff:g id="COUNT">^2</xliff:g> פריטים?</item>
<item quantity="one">לאפשר לאפליקציה <xliff:g id="APP_NAME_0">^1</xliff:g> לשנות את הפריט הזה?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="two">מתבצע שינוי ב-<xliff:g id="COUNT">^1</xliff:g> פריטים…</item>
+ <item quantity="many">מתבצע שינוי ב-<xliff:g id="COUNT">^1</xliff:g> פריטים…</item>
+ <item quantity="other">מתבצע שינוי ב-<xliff:g id="COUNT">^1</xliff:g> פריטים…</item>
+ <item quantity="one">מתבצע שינוי בפריט אחד…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="two">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> להעביר <xliff:g id="COUNT">^2</xliff:g> קובצי אודיו לאשפה?</item>
<item quantity="many">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> להעביר <xliff:g id="COUNT">^2</xliff:g> קובצי אודיו לאשפה?</item>
<item quantity="other">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> להעביר <xliff:g id="COUNT">^2</xliff:g> קובצי אודיו לאשפה?</item>
<item quantity="one">לאפשר לאפליקציה <xliff:g id="APP_NAME_0">^1</xliff:g> להעביר את קובץ האודיו הזה לאשפה?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="two">מתבצעת העברה של <xliff:g id="COUNT">^1</xliff:g> קובצי אודיו לאשפה…</item>
+ <item quantity="many">מתבצעת העברה של <xliff:g id="COUNT">^1</xliff:g> קובצי אודיו לאשפה…</item>
+ <item quantity="other">מתבצעת העברה של <xliff:g id="COUNT">^1</xliff:g> קובצי אודיו לאשפה…</item>
+ <item quantity="one">מתבצעת העברה של קובץ אודיו אחד לאשפה…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="two">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> להעביר <xliff:g id="COUNT">^2</xliff:g> סרטונים לאשפה?</item>
<item quantity="many">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> להעביר <xliff:g id="COUNT">^2</xliff:g> סרטונים לאשפה?</item>
<item quantity="other">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> להעביר <xliff:g id="COUNT">^2</xliff:g> סרטונים לאשפה?</item>
<item quantity="one">לאפשר לאפליקציה <xliff:g id="APP_NAME_0">^1</xliff:g> להעביר את הסרטון הזה לאשפה?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="two">מתבצעת העברה של <xliff:g id="COUNT">^1</xliff:g> סרטונים לאשפה…</item>
+ <item quantity="many">מתבצעת העברה של <xliff:g id="COUNT">^1</xliff:g> סרטונים לאשפה…</item>
+ <item quantity="other">מתבצעת העברה של <xliff:g id="COUNT">^1</xliff:g> סרטונים לאשפה…</item>
+ <item quantity="one">מתבצעת העברה של סרטון אחד לאשפה…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="two">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> להעביר <xliff:g id="COUNT">^2</xliff:g> תמונות לאשפה?</item>
<item quantity="many">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> להעביר <xliff:g id="COUNT">^2</xliff:g> תמונות לאשפה?</item>
<item quantity="other">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> להעביר <xliff:g id="COUNT">^2</xliff:g> תמונות לאשפה?</item>
<item quantity="one">לאפשר לאפליקציה <xliff:g id="APP_NAME_0">^1</xliff:g> להעביר את התמונה הזו לאשפה?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="two">מתבצעת העברה של <xliff:g id="COUNT">^1</xliff:g> תמונות לאשפה…</item>
+ <item quantity="many">מתבצעת העברה של <xliff:g id="COUNT">^1</xliff:g> תמונות לאשפה…</item>
+ <item quantity="other">מתבצעת העברה של <xliff:g id="COUNT">^1</xliff:g> תמונות לאשפה…</item>
+ <item quantity="one">מתבצעת העברה של תמונה אחת לאשפה…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="two">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> להעביר <xliff:g id="COUNT">^2</xliff:g> פריטים לאשפה?</item>
<item quantity="many">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> להעביר <xliff:g id="COUNT">^2</xliff:g> פריטים לאשפה?</item>
<item quantity="other">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> להעביר <xliff:g id="COUNT">^2</xliff:g> פריטים לאשפה?</item>
<item quantity="one">לאפשר לאפליקציה <xliff:g id="APP_NAME_0">^1</xliff:g> להעביר את הפריט הזה לאשפה?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="two">מתבצעת העברה של <xliff:g id="COUNT">^1</xliff:g> פריטים לאשפה…</item>
+ <item quantity="many">מתבצעת העברה של <xliff:g id="COUNT">^1</xliff:g> פריטים לאשפה…</item>
+ <item quantity="other">מתבצעת העברה של <xliff:g id="COUNT">^1</xliff:g> פריטים לאשפה…</item>
+ <item quantity="one">מתבצעת העברה של פריט אחד לאשפה…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="two">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> להוציא <xliff:g id="COUNT">^2</xliff:g> קובצי אודיו מהאשפה?</item>
<item quantity="many">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> להוציא <xliff:g id="COUNT">^2</xliff:g> קובצי אודיו מהאשפה?</item>
<item quantity="other">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> להוציא <xliff:g id="COUNT">^2</xliff:g> קובצי אודיו מהאשפה?</item>
<item quantity="one">לאפשר לאפליקציה <xliff:g id="APP_NAME_0">^1</xliff:g> להוציא את קובץ האודיו הזה מהאשפה?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="two">מתבצעת הוצאה של <xliff:g id="COUNT">^1</xliff:g> קובצי אודיו מהאשפה…</item>
+ <item quantity="many">מתבצעת הוצאה של <xliff:g id="COUNT">^1</xliff:g> קובצי אודיו מהאשפה…</item>
+ <item quantity="other">מתבצעת הוצאה של <xliff:g id="COUNT">^1</xliff:g> קובצי אודיו מהאשפה…</item>
+ <item quantity="one">מתבצעת הוצאה של קובץ אודיו אחד מהאשפה…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="two">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> להוציא <xliff:g id="COUNT">^2</xliff:g> סרטונים מהאשפה?</item>
<item quantity="many">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> להוציא <xliff:g id="COUNT">^2</xliff:g> סרטונים מהאשפה?</item>
<item quantity="other">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> להוציא <xliff:g id="COUNT">^2</xliff:g> סרטונים מהאשפה?</item>
<item quantity="one">לאפשר לאפליקציה <xliff:g id="APP_NAME_0">^1</xliff:g> להוציא את הסרטון הזה מהאשפה?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="two">מתבצעת הוצאה של <xliff:g id="COUNT">^1</xliff:g> סרטונים מהאשפה…</item>
+ <item quantity="many">מתבצעת הוצאה של <xliff:g id="COUNT">^1</xliff:g> סרטונים מהאשפה…</item>
+ <item quantity="other">מתבצעת הוצאה של <xliff:g id="COUNT">^1</xliff:g> סרטונים מהאשפה…</item>
+ <item quantity="one">מתבצעת הוצאה של סרטון אחד מהאשפה…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="two">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> להוציא <xliff:g id="COUNT">^2</xliff:g> תמונות מהאשפה?</item>
<item quantity="many">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> להוציא <xliff:g id="COUNT">^2</xliff:g> תמונות מהאשפה?</item>
<item quantity="other">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> להוציא <xliff:g id="COUNT">^2</xliff:g> תמונות מהאשפה?</item>
<item quantity="one">לאפשר לאפליקציה <xliff:g id="APP_NAME_0">^1</xliff:g> להוציא את התמונה הזו מהאשפה?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="two">מתבצעת הוצאה של <xliff:g id="COUNT">^1</xliff:g> תמונות מהאשפה…</item>
+ <item quantity="many">מתבצעת הוצאה של <xliff:g id="COUNT">^1</xliff:g> תמונות מהאשפה…</item>
+ <item quantity="other">מתבצעת הוצאה של <xliff:g id="COUNT">^1</xliff:g> תמונות מהאשפה…</item>
+ <item quantity="one">מתבצעת הוצאה של תמונה אחת מהאשפה…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="two">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> להוציא <xliff:g id="COUNT">^2</xliff:g> פריטים מהאשפה?</item>
<item quantity="many">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> להוציא <xliff:g id="COUNT">^2</xliff:g> פריטים מהאשפה?</item>
<item quantity="other">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> להוציא <xliff:g id="COUNT">^2</xliff:g> פריטים מהאשפה?</item>
<item quantity="one">לאפשר לאפליקציה <xliff:g id="APP_NAME_0">^1</xliff:g> להוציא את הפריט הזה מהאשפה?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="two">מתבצעת הוצאה של <xliff:g id="COUNT">^1</xliff:g> פריטים מהאשפה…</item>
+ <item quantity="many">מתבצעת הוצאה של <xliff:g id="COUNT">^1</xliff:g> פריטים מהאשפה…</item>
+ <item quantity="other">מתבצעת הוצאה של <xliff:g id="COUNT">^1</xliff:g> פריטים מהאשפה…</item>
+ <item quantity="one">מתבצעת הוצאה של פריט אחד מהאשפה…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="two">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> למחוק <xliff:g id="COUNT">^2</xliff:g> קובצי אודיו?</item>
<item quantity="many">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> למחוק <xliff:g id="COUNT">^2</xliff:g> קובצי אודיו?</item>
<item quantity="other">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> למחוק <xliff:g id="COUNT">^2</xliff:g> קובצי אודיו?</item>
<item quantity="one">לאפשר לאפליקציה <xliff:g id="APP_NAME_0">^1</xliff:g> למחוק את קובץ האודיו הזה?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="two">מתבצעת מחיקה של <xliff:g id="COUNT">^1</xliff:g> קובצי אודיו…</item>
+ <item quantity="many">מתבצעת מחיקה של <xliff:g id="COUNT">^1</xliff:g> קובצי אודיו…</item>
+ <item quantity="other">מתבצעת מחיקה של <xliff:g id="COUNT">^1</xliff:g> קובצי אודיו…</item>
+ <item quantity="one">מתבצעת מחיקה של קובץ אודיו אחד…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="two">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> למחוק <xliff:g id="COUNT">^2</xliff:g> סרטונים?</item>
<item quantity="many">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> למחוק <xliff:g id="COUNT">^2</xliff:g> סרטונים?</item>
<item quantity="other">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> למחוק <xliff:g id="COUNT">^2</xliff:g> סרטונים?</item>
<item quantity="one">לאפשר לאפליקציה <xliff:g id="APP_NAME_0">^1</xliff:g> למחוק את הסרטון הזה?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="two">מתבצעת מחיקה של <xliff:g id="COUNT">^1</xliff:g> סרטונים…</item>
+ <item quantity="many">מתבצעת מחיקה של <xliff:g id="COUNT">^1</xliff:g> סרטונים…</item>
+ <item quantity="other">מתבצעת מחיקה של <xliff:g id="COUNT">^1</xliff:g> סרטונים…</item>
+ <item quantity="one">מתבצעת מחיקה של סרטון אחד</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="two">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> למחוק <xliff:g id="COUNT">^2</xliff:g> תמונות?</item>
<item quantity="many">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> למחוק <xliff:g id="COUNT">^2</xliff:g> תמונות?</item>
<item quantity="other">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> למחוק <xliff:g id="COUNT">^2</xliff:g> תמונות?</item>
<item quantity="one">לאפשר לאפליקציה <xliff:g id="APP_NAME_0">^1</xliff:g> למחוק את התמונה הזו?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="two">מתבצעת מחיקה של <xliff:g id="COUNT">^1</xliff:g> תמונות…</item>
+ <item quantity="many">מתבצעת מחיקה של <xliff:g id="COUNT">^1</xliff:g> תמונות…</item>
+ <item quantity="other">מתבצעת מחיקה של <xliff:g id="COUNT">^1</xliff:g> תמונות…</item>
+ <item quantity="one">מתבצעת מחיקה של תמונה אחת…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="two">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> למחוק <xliff:g id="COUNT">^2</xliff:g> פריטים?</item>
<item quantity="many">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> למחוק <xliff:g id="COUNT">^2</xliff:g> פריטים?</item>
<item quantity="other">לאפשר לאפליקציה <xliff:g id="APP_NAME_1">^1</xliff:g> למחוק <xliff:g id="COUNT">^2</xliff:g> פריטים?</item>
<item quantity="one">לאפשר לאפליקציה <xliff:g id="APP_NAME_0">^1</xliff:g> למחוק את הפריט הזה?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="two">מתבצעת מחיקה של <xliff:g id="COUNT">^1</xliff:g> פריטים…</item>
+ <item quantity="many">מתבצעת מחיקה של <xliff:g id="COUNT">^1</xliff:g> פריטים…</item>
+ <item quantity="other">מתבצעת מחיקה של <xliff:g id="COUNT">^1</xliff:g> פריטים…</item>
+ <item quantity="one">מתבצעת מחיקה של פריט אחד…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"האפליקציה <xliff:g id="APP_NAME">%s</xliff:g> לא יכולה לעבד קובצי מדיה"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"עיבוד המדיה בוטל"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"שגיאה בעיבוד המדיה"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"עיבוד המדיה הסתיים בהצלחה"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"עיבוד המדיה החל"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"המדיה בעיבוד…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"ביטול"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"המתנה"</string>
</resources>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 481c730..e17e1e5 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> 件の音声ファイルの変更を <xliff:g id="APP_NAME_1">^1</xliff:g> に許可しますか?</item>
<item quantity="one">この音声ファイルの変更を <xliff:g id="APP_NAME_0">^1</xliff:g> に許可しますか?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> 件の音声ファイルを変更しています…</item>
+ <item quantity="one">音声ファイルを変更しています…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> 本の動画の変更を <xliff:g id="APP_NAME_1">^1</xliff:g> に許可しますか?</item>
<item quantity="one">この動画の変更を <xliff:g id="APP_NAME_0">^1</xliff:g> に許可しますか?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> 本の動画を変更しています…</item>
+ <item quantity="one">動画を変更しています…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> 枚の写真の変更を <xliff:g id="APP_NAME_1">^1</xliff:g> に許可しますか?</item>
<item quantity="one">この写真の変更を <xliff:g id="APP_NAME_0">^1</xliff:g> に許可しますか?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> 枚の写真を変更しています…</item>
+ <item quantity="one">写真を変更しています…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> 件のアイテムの変更を <xliff:g id="APP_NAME_1">^1</xliff:g> に許可しますか?</item>
<item quantity="one">このアイテムの変更を <xliff:g id="APP_NAME_0">^1</xliff:g> に許可しますか?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> 件のアイテムを変更しています…</item>
+ <item quantity="one">アイテムを変更しています…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> 件の音声ファイルをゴミ箱に移動することを <xliff:g id="APP_NAME_1">^1</xliff:g> に許可しますか?</item>
<item quantity="one">この音声ファイルをゴミ箱に移動することを <xliff:g id="APP_NAME_0">^1</xliff:g> に許可しますか?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> 件の音声ファイルをゴミ箱に移動しています…</item>
+ <item quantity="one">音声ファイルをゴミ箱に移動しています…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> 本の動画をゴミ箱に移動することを <xliff:g id="APP_NAME_1">^1</xliff:g> に許可しますか?</item>
<item quantity="one">この動画をゴミ箱に移動することを <xliff:g id="APP_NAME_0">^1</xliff:g> に許可しますか?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> 本の動画をゴミ箱に移動しています…</item>
+ <item quantity="one">動画をゴミ箱に移動しています…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> 枚の写真をゴミ箱に移動することを <xliff:g id="APP_NAME_1">^1</xliff:g> に許可しますか?</item>
<item quantity="one">この写真をゴミ箱に移動することを <xliff:g id="APP_NAME_0">^1</xliff:g> に許可しますか?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> 枚の写真をゴミ箱に移動しています…</item>
+ <item quantity="one">写真をゴミ箱に移動しています…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> 件のアイテムをゴミ箱に移動することを <xliff:g id="APP_NAME_1">^1</xliff:g> に許可しますか?</item>
<item quantity="one">このアイテムをゴミ箱に移動することを <xliff:g id="APP_NAME_0">^1</xliff:g> に許可しますか?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> 件のアイテムをゴミ箱に移動しています…</item>
+ <item quantity="one">アイテムをゴミ箱に移動しています…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> 件の音声ファイルをゴミ箱から移動することを <xliff:g id="APP_NAME_1">^1</xliff:g> に許可しますか?</item>
<item quantity="one">この音声ファイルをゴミ箱から移動することを <xliff:g id="APP_NAME_0">^1</xliff:g> に許可しますか?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> 件の音声ファイルをゴミ箱から移動しています…</item>
+ <item quantity="one">音声ファイルをゴミ箱から移動しています…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> 本の動画をゴミ箱から移動することを <xliff:g id="APP_NAME_1">^1</xliff:g> に許可しますか?</item>
<item quantity="one">この動画をゴミ箱から移動することを <xliff:g id="APP_NAME_0">^1</xliff:g> に許可しますか?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> 本の動画をゴミ箱から移動しています…</item>
+ <item quantity="one">動画をゴミ箱から移動しています…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> 枚の写真をゴミ箱から移動することを <xliff:g id="APP_NAME_1">^1</xliff:g> に許可しますか?</item>
<item quantity="one">この写真をゴミ箱から移動することを <xliff:g id="APP_NAME_0">^1</xliff:g> に許可しますか?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> 枚の写真をゴミ箱から移動しています…</item>
+ <item quantity="one">写真をゴミ箱から移動しています…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> 件のアイテムをゴミ箱から移動することを <xliff:g id="APP_NAME_1">^1</xliff:g> に許可しますか?</item>
<item quantity="one">このアイテムをゴミ箱から移動することを <xliff:g id="APP_NAME_0">^1</xliff:g> に許可しますか?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> 件のアイテムをゴミ箱から移動しています…</item>
+ <item quantity="one">アイテムをゴミ箱から移動しています…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> 件の音声ファイルの削除を <xliff:g id="APP_NAME_1">^1</xliff:g> に許可しますか?</item>
<item quantity="one">この音声ファイルの削除を <xliff:g id="APP_NAME_0">^1</xliff:g> に許可しますか?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> 件の音声ファイルを削除しています…</item>
+ <item quantity="one">音声ファイルを削除しています…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> 本の動画の削除を <xliff:g id="APP_NAME_1">^1</xliff:g> に許可しますか?</item>
<item quantity="one">この動画の削除を <xliff:g id="APP_NAME_0">^1</xliff:g> に許可しますか?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> 本の動画を削除しています…</item>
+ <item quantity="one">動画を削除しています…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> 枚の写真の削除を <xliff:g id="APP_NAME_1">^1</xliff:g> に許可しますか?</item>
<item quantity="one">この写真の削除を <xliff:g id="APP_NAME_0">^1</xliff:g> に許可しますか?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> 枚の写真を削除しています…</item>
+ <item quantity="one">写真を削除しています…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> 件のアイテムの削除を <xliff:g id="APP_NAME_1">^1</xliff:g> に許可しますか?</item>
<item quantity="one">このアイテムの削除を <xliff:g id="APP_NAME_0">^1</xliff:g> に許可しますか?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> 件のアイテムを削除しています…</item>
+ <item quantity="one">アイテムを削除しています…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g>はメディア ファイルを処理できません"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"メディアの処理をキャンセルしました"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"メディア処理エラー"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"メディアの処理が終わりました"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"メディアの処理を開始しました"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"メディアを処理しています…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"キャンセル"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"待機"</string>
</resources>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index 420e846..d7d8808 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">აძლევთ უფლებას <xliff:g id="APP_NAME_1">^1</xliff:g>-ს, შეცვალოს <xliff:g id="COUNT">^2</xliff:g> აუდიოფაილი?</item>
<item quantity="one">აძლევთ უფლებას <xliff:g id="APP_NAME_0">^1</xliff:g>-ს, შეცვალოს ეს აუდიოფაილი?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other">მიმდინარეობს <xliff:g id="COUNT">^1</xliff:g> აუდიოფაილის მოდიფიკაცია…</item>
+ <item quantity="one">მიმდინარეობს აუდიოფაილის მოდიფიკაცია…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">აძლევთ უფლებას <xliff:g id="APP_NAME_1">^1</xliff:g>-ს, შეცვალოს <xliff:g id="COUNT">^2</xliff:g> ვიდეო?</item>
<item quantity="one">აძლევთ უფლებას <xliff:g id="APP_NAME_0">^1</xliff:g>-ს, შეცვალოს ეს ვიდეო?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other">მიმდინარეობს <xliff:g id="COUNT">^1</xliff:g> ვიდეოს მოდიფიკაცია…</item>
+ <item quantity="one">მიმდინარეობს ვიდეოს მოდიფიკაცია…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">აძლევთ უფლებას <xliff:g id="APP_NAME_1">^1</xliff:g>-ს, შეცვალოს <xliff:g id="COUNT">^2</xliff:g> ფოტო?</item>
<item quantity="one">აძლევთ უფლებას <xliff:g id="APP_NAME_0">^1</xliff:g>-ს, შეცვალოს ეს ფოტო?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other">მიმდინარეობს <xliff:g id="COUNT">^1</xliff:g> ფოტოს მოდიფიკაცია…</item>
+ <item quantity="one">მიმდინარეობს ფოტოს მოდიფიკაცია…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">აძლევთ უფლებას <xliff:g id="APP_NAME_1">^1</xliff:g>-ს, შეცვალოს <xliff:g id="COUNT">^2</xliff:g> ერთეული?</item>
<item quantity="one">აძლევთ უფლებას <xliff:g id="APP_NAME_0">^1</xliff:g>-ს, შეცვალოს ეს ერთეული?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other">მიმდინარეობს <xliff:g id="COUNT">^1</xliff:g> ერთეულის მოდიფიკაცია…</item>
+ <item quantity="one">მიმდინარეობს ერთეულის მოდიფიკაცია…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">აძლევთ უფლებას <xliff:g id="APP_NAME_1">^1</xliff:g>-ს, გადაიტანოს <xliff:g id="COUNT">^2</xliff:g> აუდიოფაილი წაშლილებში?</item>
<item quantity="one">აძლევთ უფლებას <xliff:g id="APP_NAME_0">^1</xliff:g>-ს, გადაიტანოს ეს აუდიოფაილი წაშლილებში?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other">მიმდინარეობს <xliff:g id="COUNT">^1</xliff:g> აუდიოფაილის წაშლილებში გადატანა…</item>
+ <item quantity="one">მიმდინარეობს აუდიოფაილის წაშლილებში გადატანა…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">აძლევთ უფლებას <xliff:g id="APP_NAME_1">^1</xliff:g>-ს, გადაიტანოს <xliff:g id="COUNT">^2</xliff:g> ვიდეო წაშლილებში?</item>
<item quantity="one">აძლევთ უფლებას <xliff:g id="APP_NAME_0">^1</xliff:g>-ს, გადაიტანოს ეს ვიდეო წაშლილებში?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other">მიმდინარეობს <xliff:g id="COUNT">^1</xliff:g> ვიდეოს წაშლილებში გადატანა…</item>
+ <item quantity="one">მიმდინარეობს ვიდეოს წაშლილებში გადატანა…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">აძლევთ უფლებას <xliff:g id="APP_NAME_1">^1</xliff:g>-ს, გადაიტანოს <xliff:g id="COUNT">^2</xliff:g> ფოტო წაშლილებში?</item>
<item quantity="one">აძლევთ უფლებას <xliff:g id="APP_NAME_0">^1</xliff:g>-ს, გადაიტანოს ეს ფოტო წაშლილებში?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other">მიმდინარეობს <xliff:g id="COUNT">^1</xliff:g> ფოტოს წაშლილებში გადატანა…</item>
+ <item quantity="one">მიმდინარეობს ფოტოს წაშლილებში გადატანა…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">აძლევთ უფლებას <xliff:g id="APP_NAME_1">^1</xliff:g>-ს, გადაიტანოს <xliff:g id="COUNT">^2</xliff:g> ერთეული წაშლილებში?</item>
<item quantity="one">აძლევთ უფლებას <xliff:g id="APP_NAME_0">^1</xliff:g>-ს, გადაიტანოს ეს ერთეული წაშლილებში?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other">მიმდინარეობს <xliff:g id="COUNT">^1</xliff:g> ერთეულის წაშლილებში გადატანა…</item>
+ <item quantity="one">მიმდინარეობს ერთეულის წაშლილებში გადატანა…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">აძლევთ უფლებას <xliff:g id="APP_NAME_1">^1</xliff:g>-ს, გადმოიტანოს <xliff:g id="COUNT">^2</xliff:g> აუდიოფაილი წაშლილებიდან?</item>
<item quantity="one">აძლევთ უფლებას <xliff:g id="APP_NAME_0">^1</xliff:g>-ს, გადმოიტანოს ეს აუდიოფაილი წაშლილებიდან?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other">მიმდინარეობს <xliff:g id="COUNT">^1</xliff:g> აუდიოფაილის წაშლილებიდან გადმოტანა…</item>
+ <item quantity="one">მიმდინარეობს აუდიოფაილის წაშლილებიდან გადმოტანა…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">აძლევთ უფლებას <xliff:g id="APP_NAME_1">^1</xliff:g>-ს, გადმოიტანოს <xliff:g id="COUNT">^2</xliff:g> ვიდეო წაშლილებიდან?</item>
<item quantity="one">აძლევთ უფლებას <xliff:g id="APP_NAME_0">^1</xliff:g>-ს, გადმოიტანოს ეს ვიდეო წაშლილებიდან?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other">მიმდინარეობს <xliff:g id="COUNT">^1</xliff:g> ვიდეოს წაშლილებიდან გადმოტანა…</item>
+ <item quantity="one">მიმდინარეობს ვიდეოს წაშლილებიდან გადმოტანა…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">აძლევთ უფლებას <xliff:g id="APP_NAME_1">^1</xliff:g>-ს, გადმოიტანოს <xliff:g id="COUNT">^2</xliff:g> ფოტო წაშლილებიდან?</item>
<item quantity="one">აძლევთ უფლებას <xliff:g id="APP_NAME_0">^1</xliff:g>-ს, გადმოიტანოს ეს ფოტო წაშლილებიდან?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other">მიმდინარეობს <xliff:g id="COUNT">^1</xliff:g> ფოტოს წაშლილებიდან გადმოტანა…</item>
+ <item quantity="one">მიმდინარეობს ფოტოს წაშლილებიდან გადმოტანა…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">აძლევთ უფლებას <xliff:g id="APP_NAME_1">^1</xliff:g>-ს, გადმოიტანოს <xliff:g id="COUNT">^2</xliff:g> ერთეული წაშლილებიდან?</item>
<item quantity="one">აძლევთ უფლებას <xliff:g id="APP_NAME_0">^1</xliff:g>-ს, გადმოიტანოს ეს ერთეული წაშლილებიდან?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other">მიმდინარეობს <xliff:g id="COUNT">^1</xliff:g> ერთეულის წაშლილებიდან გადმოტანა…</item>
+ <item quantity="one">მიმდინარეობს ერთეულის წაშლილებიდან გადმოტანა…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">აძლევთ უფლებას <xliff:g id="APP_NAME_1">^1</xliff:g>-ს, წაშალოს <xliff:g id="COUNT">^2</xliff:g> აუდიოფაილი?</item>
<item quantity="one">აძლევთ უფლებას <xliff:g id="APP_NAME_0">^1</xliff:g>-ს, წაშალოს ეს აუდიოფაილი?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other">მიმდინარეობს <xliff:g id="COUNT">^1</xliff:g> აუდიოფაილის წაშლა…</item>
+ <item quantity="one">მიმდინარეობს აუდიოფაილის წაშლა…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">აძლევთ უფლებას <xliff:g id="APP_NAME_1">^1</xliff:g>-ს, წაშალოს <xliff:g id="COUNT">^2</xliff:g> ვიდეო?</item>
<item quantity="one">აძლევთ უფლებას <xliff:g id="APP_NAME_0">^1</xliff:g>-ს, წაშალოს ეს ვიდეო?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other">მიმდინარეობს <xliff:g id="COUNT">^1</xliff:g> ვიდეოს წაშლა…</item>
+ <item quantity="one">მიმდინარეობს ვიდეოს წაშლა…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">აძლევთ უფლებას <xliff:g id="APP_NAME_1">^1</xliff:g>-ს, წაშალოს <xliff:g id="COUNT">^2</xliff:g> ფოტო?</item>
<item quantity="one">აძლევთ უფლებას <xliff:g id="APP_NAME_0">^1</xliff:g>-ს, წაშალოს ეს ფოტო?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other">მიმდინარეობს <xliff:g id="COUNT">^1</xliff:g> ფოტოს წაშლა…</item>
+ <item quantity="one">მიმდინარეობს ფოტოს წაშლა…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">აძლევთ უფლებას <xliff:g id="APP_NAME_1">^1</xliff:g>-ს, წაშალოს <xliff:g id="COUNT">^2</xliff:g> ერთეული?</item>
<item quantity="one">აძლევთ უფლებას <xliff:g id="APP_NAME_0">^1</xliff:g>-ს, წაშალოს ეს ერთეული?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other">მიმდინარეობს <xliff:g id="COUNT">^1</xliff:g> ერთეულის წაშლა…</item>
+ <item quantity="one">მიმდინარეობს ერთეულის წაშლა…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> ვერ ამუშავებს მედია ფაილებს"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"მედიის დამუშავება გაუქმდა"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"მედიის დამუშავებისას შეცდომა მოხდა"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"მედიის დამუშავება წარმატებით დასრულდა"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"მედიის დამუშავება დაიწყო"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"მედია მუშავდება…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"გაუქმება"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"მოცდა"</string>
</resources>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 1b899b2..f6a9252 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> қолданбасына <xliff:g id="COUNT">^2</xliff:g> аудиофайлды өзгертуге рұқсат етесіз бе?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> қолданбасына осы аудиофайлды өзгертуге рұқсат етесіз бе?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> аудиофайл өзгертілуде…</item>
+ <item quantity="one">Аудиофайл өзгертілуде…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> қолданбасына <xliff:g id="COUNT">^2</xliff:g> бейнені өзгертуге рұқсат етесіз бе?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> қолданбасына осы бейнені өзгертуге рұқсат етесіз бе?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> бейне өзгертілуде…</item>
+ <item quantity="one">Бейне өзгертілуде…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> қолданбасына <xliff:g id="COUNT">^2</xliff:g> фотосуретті өзгертуге рұқсат етесіз бе?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> қолданбасына осы фотосуретті өзгертуге рұқсат етесіз бе?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> фотосурет өзгертілуде…</item>
+ <item quantity="one">Фотосурет өзгертілуде…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> қолданбасына <xliff:g id="COUNT">^2</xliff:g> элементті өзгертуге рұқсат етесіз бе?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> қолданбасына осы элементті өзгертуге рұқсат етесіз бе?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> элемент өзгертілуде…</item>
+ <item quantity="one">Элемент өзгертілуде…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> қолданбасына <xliff:g id="COUNT">^2</xliff:g> аудиофайлды себетке жіберуге рұқсат етесіз бе?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> қолданбасына осы аудиофайлды себетке жіберуге рұқсат етесіз бе?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> аудиофайл себетке жіберілуде…</item>
+ <item quantity="one">Аудиофайл себетке жіберілуде…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> қолданбасына <xliff:g id="COUNT">^2</xliff:g> бейнені себетке жіберуге рұқсат етесіз бе?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> қолданбасына осы бейнені себетке жіберуге рұқсат етесіз бе?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> бейне себетке жіберілуде…</item>
+ <item quantity="one">Бейне себетке жіберілуде…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> қолданбасына <xliff:g id="COUNT">^2</xliff:g> фотосуретті себетке жіберуге рұқсат етесіз бе?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> қолданбасына осы фотосуретті себетке жіберуге рұқсат етесіз бе?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> фотосурет себетке жіберілуде…</item>
+ <item quantity="one">Фотосурет себетке жіберілуде…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> қолданбасына <xliff:g id="COUNT">^2</xliff:g> элементті себетке жіберуге рұқсат етесіз бе?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> қолданбасына осы элементті себетке жіберуге рұқсат етесіз бе?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> элемент себетке жіберілуде…</item>
+ <item quantity="one">Элемент себетке жіберілуде…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> қолданбасына <xliff:g id="COUNT">^2</xliff:g> аудиофайлды себеттен шығаруға рұқсат етесіз бе?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> қолданбасына бұл аудиофайлды себеттен шығаруға рұқсат етесіз бе?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> аудиофайл себеттен шығарылуда…</item>
+ <item quantity="one">Аудиофайл себеттен шығарылуда…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> қолданбасына <xliff:g id="COUNT">^2</xliff:g> бейнені себеттен шығаруға рұқсат етесіз бе?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> қолданбасына осы бейнені себеттен шығаруға рұқсат етесіз бе?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> бейне себеттен шығарылуда…</item>
+ <item quantity="one">Бейне себеттен шығарылуда…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> қолданбасына <xliff:g id="COUNT">^2</xliff:g> фотосуретті себеттен шығаруға рұқсат етесіз бе?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> қолданбасына осы фотосуретті себеттен шығаруға рұқсат етесіз бе?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> фотосурет себеттен шығарылуда…</item>
+ <item quantity="one">Фотосурет себеттен шығарылуда…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> қолданбасына <xliff:g id="COUNT">^2</xliff:g> элементті себеттен шығаруға рұқсат етесіз бе?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> қолданбасына осы элементті себеттен шығаруға рұқсат етесіз бе?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> элемент себеттен шығарылуда…</item>
+ <item quantity="one">Элемент себеттен шығарылуда…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> қолданбасына <xliff:g id="COUNT">^2</xliff:g> аудиофайлды жоюға рұқсат етесіз бе?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> қолданбасына осы аудиофайлды жоюға рұқсат етесіз бе?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> аудиофайл жойылуда…</item>
+ <item quantity="one">Аудиофайл жойылуда…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> қолданбасына <xliff:g id="COUNT">^2</xliff:g> бейнені жоюға рұқсат етесіз бе?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> қолданбасына осы бейнені жоюға рұқсат етесіз бе?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> бейне жойылуда…</item>
+ <item quantity="one">Бейне жойылуда…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> қолданбасына <xliff:g id="COUNT">^2</xliff:g> фотосуретті жоюға рұқсат етесіз бе?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> қолданбасына осы фотосуретті жоюға рұқсат етесіз бе?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> фотосурет жойылуда…</item>
+ <item quantity="one">Фотосурет жойылуда…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> қолданбасына <xliff:g id="COUNT">^2</xliff:g> элементті жоюға рұқсат етесіз бе?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> қолданбасына осы элементті жоюға рұқсат етесіз бе?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> элемент жойылуда…</item>
+ <item quantity="one">Элемент жойылуда…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> қолданбасы медиа файлдарды өңдей алмайды."</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Медиафайлды өңдеу тоқтатылды."</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Медиафайлды өңдеуде қате пайда болды."</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Медиафайл сәтті өңделді."</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Медиафайлды өңдеу басталды."</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Медиафайл өңделуде…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Бас тарту"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Күту"</string>
</resources>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index b4a930f..d7662d6 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_1">^1</xliff:g> កែឯកសារសំឡេង <xliff:g id="COUNT">^2</xliff:g> ឬ?</item>
<item quantity="one">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_0">^1</xliff:g> កែឯកសារសំឡេងនេះឬ?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other">កំពុងកែឯកសារសំឡេង <xliff:g id="COUNT">^1</xliff:g>…</item>
+ <item quantity="one">កំពុងកែឯកសារសំឡេង…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_1">^1</xliff:g> កែវីដេអូ <xliff:g id="COUNT">^2</xliff:g> ឬ?</item>
<item quantity="one">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_0">^1</xliff:g> កែវីដេអូនេះឬ?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other">កំពុងកែវីដេអូ <xliff:g id="COUNT">^1</xliff:g>…</item>
+ <item quantity="one">កំពុងកែវីដេអូ…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_1">^1</xliff:g> កែរូបថត <xliff:g id="COUNT">^2</xliff:g> សន្លឹកឬ?</item>
<item quantity="one">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_0">^1</xliff:g> កែរូបថតនេះឬ?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other">កំពុងកែរូបថត <xliff:g id="COUNT">^1</xliff:g> សន្លឹក…</item>
+ <item quantity="one">កំពុងកែរូបថត…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_1">^1</xliff:g> កែធាតុ <xliff:g id="COUNT">^2</xliff:g> ឬ?</item>
<item quantity="one">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_0">^1</xliff:g> កែធាតុនេះឬ?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other">កំពុងកែធាតុ <xliff:g id="COUNT">^1</xliff:g>…</item>
+ <item quantity="one">កំពុងកែធាតុ…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_1">^1</xliff:g> ផ្លាស់ទីឯកសារសំឡេង <xliff:g id="COUNT">^2</xliff:g> ទៅធុងសំរាមឬ?</item>
<item quantity="one">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_0">^1</xliff:g> ផ្លាស់ទីឯកសារសំឡេងនេះទៅធុងសំរាមឬ?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other">កំពុងផ្លាស់ទីឯកសារសំឡេង <xliff:g id="COUNT">^1</xliff:g> ទៅធុងសំរាម…</item>
+ <item quantity="one">កំពុងផ្លាស់ទីឯកសារសំឡេងទៅធុងសំរាម…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_1">^1</xliff:g> ផ្លាស់ទីវីដេអូ <xliff:g id="COUNT">^2</xliff:g> ទៅធុងសំរាមឬ?</item>
<item quantity="one">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_0">^1</xliff:g> ផ្លាស់ទីវីដេអូនេះទៅធុងសំរាមឬ?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other">កំពុងផ្លាស់ទីវីដេអូ <xliff:g id="COUNT">^1</xliff:g> ទៅធុងសំរាម…</item>
+ <item quantity="one">កំពុងផ្លាស់ទីវីដេអូទៅធុងសំរាម…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_1">^1</xliff:g> ផ្លាស់ទីរូបថត <xliff:g id="COUNT">^2</xliff:g> សន្លឹកទៅធុងសំរាមឬ?</item>
<item quantity="one">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_0">^1</xliff:g> ផ្លាស់ទីរូបថតនេះទៅធុងសំរាមឬ?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other">កំពុងផ្លាស់ទីរូបថត <xliff:g id="COUNT">^1</xliff:g> សន្លឹកទៅធុងសំរាម…</item>
+ <item quantity="one">កំពុងផ្លាស់ទីរូបថតទៅធុងសំរាម…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_1">^1</xliff:g> ផ្លាស់ទីធាតុ <xliff:g id="COUNT">^2</xliff:g> ទៅធុងសំរាមឬ?</item>
<item quantity="one">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_0">^1</xliff:g> ផ្លាស់ទីធាតុនេះទៅធុងសំរាមឬ?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other">កំពុងផ្លាស់ទីធាតុ <xliff:g id="COUNT">^1</xliff:g> ទៅធុងសំរាម…</item>
+ <item quantity="one">កំពុងផ្លាស់ទីធាតុទៅធុងសំរាម…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_1">^1</xliff:g> ផ្លាស់ទីឯកសារសំឡេង <xliff:g id="COUNT">^2</xliff:g> ចេញពីធុងសំរាមឬ?</item>
<item quantity="one">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_0">^1</xliff:g> ផ្លាស់ទីឯកសារសំឡេងនេះចេញពីធុងសំរាមឬ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other">កំពុងផ្លាស់ទីឯកសារសំឡេង <xliff:g id="COUNT">^1</xliff:g> ចេញពីធុងសំរាម…</item>
+ <item quantity="one">កំពុងផ្លាស់ទីឯកសារសំឡេងចេញពីធុងសំរាម…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_1">^1</xliff:g> ផ្លាស់ទីវីដេអូ <xliff:g id="COUNT">^2</xliff:g> ចេញពីធុងសំរាមឬ?</item>
<item quantity="one">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_0">^1</xliff:g> ផ្លាស់ទីវីដេអូនេះចេញពីធុងសំរាមឬ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other">កំពុងផ្លាស់ទីវីដេអូ <xliff:g id="COUNT">^1</xliff:g> ចេញពីធុងសំរាម…</item>
+ <item quantity="one">កំពុងផ្លាស់ទីវីដេអូចេញពីធុងសំរាម…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_1">^1</xliff:g> ផ្លាស់ទីរូបថត <xliff:g id="COUNT">^2</xliff:g> សន្លឹកចេញពីធុងសំរាមឬ?</item>
<item quantity="one">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_0">^1</xliff:g> ផ្លាស់ទីរូបថតនេះចេញពីធុងសំរាមឬ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other">កំពុងផ្លាស់ទីរូបថត <xliff:g id="COUNT">^1</xliff:g> សន្លឹកចេញពីធុងសំរាម…</item>
+ <item quantity="one">កំពុងផ្លាស់ទីរូបថតចេញពីធុងសំរាម…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_1">^1</xliff:g> ផ្លាស់ទីធាតុ <xliff:g id="COUNT">^2</xliff:g> ចេញពីធុងសំរាមឬ?</item>
<item quantity="one">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_0">^1</xliff:g> ផ្លាស់ទីធាតុនេះចេញពីធុងសំរាមឬ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other">កំពុងផ្លាស់ទីធាតុ <xliff:g id="COUNT">^1</xliff:g> ចេញពីធុងសំរាម…</item>
+ <item quantity="one">កំពុងផ្លាស់ទីធាតុចេញពីធុងសំរាម…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_1">^1</xliff:g> លុបឯកសារសំឡេង <xliff:g id="COUNT">^2</xliff:g> ឬ?</item>
<item quantity="one">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_0">^1</xliff:g> លុបឯកសារសំឡេងនេះឬ?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other">កំពុងលុបឯកសារសំឡេង <xliff:g id="COUNT">^1</xliff:g>…</item>
+ <item quantity="one">កំពុងលុបឯកសារសំឡេង…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_1">^1</xliff:g> លុបវីដេអូ <xliff:g id="COUNT">^2</xliff:g> ឬ?</item>
<item quantity="one">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_0">^1</xliff:g> លុបវីដេអូនេះឬ?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other">កំពុងលុបវីដេអូ <xliff:g id="COUNT">^1</xliff:g>…</item>
+ <item quantity="one">កំពុងលុបវីដេអូ…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_1">^1</xliff:g> លុបរូបថត <xliff:g id="COUNT">^2</xliff:g> សន្លឹកឬ?</item>
<item quantity="one">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_0">^1</xliff:g> លុបរូបថតនេះឬ?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other">កំពុងលុបរូបថត <xliff:g id="COUNT">^1</xliff:g>…</item>
+ <item quantity="one">កំពុងលុបរូបថត…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_1">^1</xliff:g> លុបធាតុ <xliff:g id="COUNT">^2</xliff:g> ឬ?</item>
<item quantity="one">អនុញ្ញាតឱ្យ <xliff:g id="APP_NAME_0">^1</xliff:g> លុបធាតុនេះឬ?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other">កំពុងលុបធាតុ <xliff:g id="COUNT">^1</xliff:g>…</item>
+ <item quantity="one">កំពុងលុបធាតុ…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> មិនអាចដំណើរការឯកសារមេឌៀបានទេ"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"បានបោះបង់ការដំណើរការមេឌៀ"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"មានបញ្ហាក្នុងការដំណើរការមេឌៀ"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"ការដំណើរការមេឌៀជោគជ័យហើយ"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"បានចាប់ផ្ដើមការដំណើរការមេឌៀ"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"កំពុងដំណើរការមេឌៀ…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"បោះបង់"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"រង់ចាំ"</string>
</resources>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 99c1788..ca1da24 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -47,64 +47,136 @@
<item quantity="one">ಈ <xliff:g id="COUNT">^2</xliff:g> ಆಡಿಯೋ ಫೈಲ್ಗಳನ್ನು ಮಾರ್ಪಡಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
<item quantity="other">ಈ <xliff:g id="COUNT">^2</xliff:g> ಆಡಿಯೋ ಫೈಲ್ಗಳನ್ನು ಮಾರ್ಪಡಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ಆಡಿಯೋ ಫೈಲ್ಗಳನ್ನು ಮಾರ್ಪಡಿಸಲಾಗುತ್ತಿದೆ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ಆಡಿಯೋ ಫೈಲ್ಗಳನ್ನು ಮಾರ್ಪಡಿಸಲಾಗುತ್ತಿದೆ…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="one">ಈ <xliff:g id="COUNT">^2</xliff:g> ವೀಡಿಯೊಗಳನ್ನು ಮಾರ್ಪಡಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
<item quantity="other">ಈ <xliff:g id="COUNT">^2</xliff:g> ವೀಡಿಯೊಗಳನ್ನು ಮಾರ್ಪಡಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ವೀಡಿಯೋಗಳನ್ನು ಮಾರ್ಪಡಿಸಲಾಗುತ್ತಿದೆ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ವೀಡಿಯೋಗಳನ್ನು ಮಾರ್ಪಡಿಸಲಾಗುತ್ತಿದೆ…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="one">ಈ <xliff:g id="COUNT">^2</xliff:g> ಫೋಟೋಗಳನ್ನು ಮಾರ್ಪಡಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
<item quantity="other">ಈ <xliff:g id="COUNT">^2</xliff:g> ಫೋಟೋಗಳನ್ನು ಮಾರ್ಪಡಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ಫೋಟೋಗಳನ್ನು ಮಾರ್ಪಡಿಸಲಾಗುತ್ತಿದೆ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ಫೋಟೋಗಳನ್ನು ಮಾರ್ಪಡಿಸಲಾಗುತ್ತಿದೆ…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="one">ಈ <xliff:g id="COUNT">^2</xliff:g> ಐಟಂಗಳನ್ನು ಮಾರ್ಪಡಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
<item quantity="other">ಈ <xliff:g id="COUNT">^2</xliff:g> ಐಟಂಗಳನ್ನು ಮಾರ್ಪಡಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ಐಟಂಗಳನ್ನು ಮಾರ್ಪಡಿಸಲಾಗುತ್ತಿದೆ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ಐಟಂಗಳನ್ನು ಮಾರ್ಪಡಿಸಲಾಗುತ್ತಿದೆ…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="one">ಈ <xliff:g id="COUNT">^2</xliff:g> ಆಡಿಯೋ ಫೈಲ್ಗಳನ್ನು ಅನುಪಯುಕ್ತಕ್ಕೆ ಸರಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
<item quantity="other">ಈ <xliff:g id="COUNT">^2</xliff:g> ಆಡಿಯೋ ಫೈಲ್ಗಳನ್ನು ಅನುಪಯುಕ್ತಕ್ಕೆ ಸರಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ಆಡಿಯೋ ಫೈಲ್ಗಳನ್ನು ಅನುಪಯುಕ್ತಕ್ಕೆ ಸರಿಸಲಾಗುತ್ತಿದೆ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ಆಡಿಯೋ ಫೈಲ್ಗಳನ್ನು ಅನುಪಯುಕ್ತಕ್ಕೆ ಸರಿಸಲಾಗುತ್ತಿದೆ…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="one">ಈ <xliff:g id="COUNT">^2</xliff:g> ವೀಡಿಯೊಗಳನ್ನು ಅನುಪಯುಕ್ತಕ್ಕೆ ಸರಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
<item quantity="other">ಈ <xliff:g id="COUNT">^2</xliff:g> ವೀಡಿಯೊಗಳನ್ನು ಅನುಪಯುಕ್ತಕ್ಕೆ ಸರಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ವೀಡಿಯೋವನ್ನು ಅನುಪಯುಕ್ತಕ್ಕೆ ಸರಿಸಲಾಗುತ್ತಿದೆ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ವೀಡಿಯೋವನ್ನು ಅನುಪಯುಕ್ತಕ್ಕೆ ಸರಿಸಲಾಗುತ್ತಿದೆ…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="one">ಈ <xliff:g id="COUNT">^2</xliff:g> ಫೋಟೋಗಳನ್ನು ಅನುಪಯುಕ್ತಕ್ಕೆ ಸರಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
<item quantity="other">ಈ <xliff:g id="COUNT">^2</xliff:g> ಫೋಟೋಗಳನ್ನು ಅನುಪಯುಕ್ತಕ್ಕೆ ಸರಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ಫೋಟೋಗಳನ್ನು ಅನುಪಯುಕ್ತಕ್ಕೆ ಸರಿಸಲಾಗುತ್ತಿದೆ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ಫೋಟೋಗಳನ್ನು ಅನುಪಯುಕ್ತಕ್ಕೆ ಸರಿಸಲಾಗುತ್ತಿದೆ…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="one">ಈ <xliff:g id="COUNT">^2</xliff:g> ಐಟಂಗಳನ್ನು ಅನುಪಯುಕ್ತಕ್ಕೆ ಸರಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
<item quantity="other">ಈ <xliff:g id="COUNT">^2</xliff:g> ಐಟಂಗಳನ್ನು ಅನುಪಯುಕ್ತಕ್ಕೆ ಸರಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ಐಟಂಗಳನ್ನು ಅನುಪಯುಕ್ತಕ್ಕೆ ಸರಿಸಲಾಗುತ್ತಿದೆ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ಐಟಂಗಳನ್ನು ಅನುಪಯುಕ್ತಕ್ಕೆ ಸರಿಸಲಾಗುತ್ತಿದೆ…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="one">ಈ <xliff:g id="COUNT">^2</xliff:g> ಆಡಿಯೋ ಫೈಲ್ಗಳನ್ನು ಅನುಪಯುಕ್ತದಿಂದ ಹೊರಗೆ ಸರಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
<item quantity="other">ಈ <xliff:g id="COUNT">^2</xliff:g> ಆಡಿಯೋ ಫೈಲ್ಗಳನ್ನು ಅನುಪಯುಕ್ತದಿಂದ ಹೊರಗೆ ಸರಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ಆಡಿಯೋ ಫೈಲ್ಗಳನ್ನು ಅನುಪಯುಕ್ತದಿಂದ ಹೊರಗೆ ಸರಿಸಲಾಗುತ್ತಿದೆ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ಆಡಿಯೋ ಫೈಲ್ಗಳನ್ನು ಅನುಪಯುಕ್ತದಿಂದ ಹೊರಗೆ ಸರಿಸಲಾಗುತ್ತಿದೆ…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="one">ಈ <xliff:g id="COUNT">^2</xliff:g> ವೀಡಿಯೊಗಳನ್ನು ಅನುಪಯುಕ್ತದಿಂದ ಹೊರಗೆ ಸರಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
<item quantity="other">ಈ <xliff:g id="COUNT">^2</xliff:g> ವೀಡಿಯೊಗಳನ್ನು ಅನುಪಯುಕ್ತದಿಂದ ಹೊರಗೆ ಸರಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ವೀಡಿಯೋಗಳನ್ನು ಅನುಪಯುಕ್ತದಿಂದ ಹೊರಗೆ ಸರಿಸಲಾಗುತ್ತಿದೆ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ವೀಡಿಯೋಗಳನ್ನು ಅನುಪಯುಕ್ತದಿಂದ ಹೊರಗೆ ಸರಿಸಲಾಗುತ್ತಿದೆ…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="one">ಈ <xliff:g id="COUNT">^2</xliff:g> ಫೋಟೋಗಳನ್ನು ಅನುಪಯುಕ್ತದಿಂದ ಹೊರಗೆ ಸರಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
<item quantity="other">ಈ <xliff:g id="COUNT">^2</xliff:g> ಫೋಟೋಗಳನ್ನು ಅನುಪಯುಕ್ತದಿಂದ ಹೊರಗೆ ಸರಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ಫೋಟೋಗಳನ್ನು ಅನುಪಯುಕ್ತದಿಂದ ಹೊರಗೆ ಸರಿಸಲಾಗುತ್ತಿದೆ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ಫೋಟೋಗಳನ್ನು ಅನುಪಯುಕ್ತದಿಂದ ಹೊರಗೆ ಸರಿಸಲಾಗುತ್ತಿದೆ…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="one">ಈ <xliff:g id="COUNT">^2</xliff:g> ಐಟಂಗಳನ್ನು ಅನುಪಯುಕ್ತದಿಂದ ಹೊರಗೆ ಸರಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
<item quantity="other">ಈ <xliff:g id="COUNT">^2</xliff:g> ಐಟಂಗಳನ್ನು ಅನುಪಯುಕ್ತದಿಂದ ಹೊರಗೆ ಸರಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ಐಟಂಗಳನ್ನು ಅನುಪಯುಕ್ತದಿಂದ ಹೊರಗೆ ಸರಿಸಲಾಗುತ್ತಿದೆ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ಐಟಂಗಳನ್ನು ಅನುಪಯುಕ್ತದಿಂದ ಹೊರಗೆ ಸರಿಸಲಾಗುತ್ತಿದೆ…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="one">ಈ <xliff:g id="COUNT">^2</xliff:g> ಆಡಿಯೋ ಫೈಲ್ಗಳನ್ನು ಅಳಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
<item quantity="other">ಈ <xliff:g id="COUNT">^2</xliff:g> ಆಡಿಯೋ ಫೈಲ್ಗಳನ್ನು ಅಳಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ಆಡಿಯೋ ಫೈಲ್ಗಳನ್ನು ಅಳಿಸಲಾಗುತ್ತಿದೆ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ಆಡಿಯೋ ಫೈಲ್ಗಳನ್ನು ಅಳಿಸಲಾಗುತ್ತಿದೆ…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="one">ಈ <xliff:g id="COUNT">^2</xliff:g> ವೀಡಿಯೊಗಳನ್ನು ಅಳಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
<item quantity="other">ಈ <xliff:g id="COUNT">^2</xliff:g> ವೀಡಿಯೊಗಳನ್ನು ಅಳಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ವೀಡಿಯೊಗಳನ್ನು ಅಳಿಸಲಾಗುತ್ತಿದೆ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ವೀಡಿಯೊಗಳನ್ನು ಅಳಿಸಲಾಗುತ್ತಿದೆ…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="one">ಈ <xliff:g id="COUNT">^2</xliff:g> ಫೋಟೋಗಳನ್ನು ಅಳಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
<item quantity="other">ಈ <xliff:g id="COUNT">^2</xliff:g> ಫೋಟೋಗಳನ್ನು ಅಳಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ಫೋಟೋಗಳನ್ನು ಅಳಿಸಲಾಗುತ್ತಿದೆ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ಫೋಟೋಗಳನ್ನು ಅಳಿಸಲಾಗುತ್ತಿದೆ…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="one">ಈ <xliff:g id="COUNT">^2</xliff:g> ಐಟಂಗಳನ್ನು ಅಳಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
<item quantity="other">ಈ <xliff:g id="COUNT">^2</xliff:g> ಐಟಂಗಳನ್ನು ಅಳಿಸಲು <xliff:g id="APP_NAME_1">^1</xliff:g> ಗೆ ಅನುಮತಿ ನೀಡಬೇಕೇ?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ಐಟಂಗಳನ್ನು ಅಳಿಸಲಾಗುತ್ತಿದೆ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ಐಟಂಗಳನ್ನು ಅಳಿಸಲಾಗುತ್ತಿದೆ…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> ಮಾಧ್ಯಮ ಫೈಲ್ಗಳನ್ನು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"ಮಾಧ್ಯಮ ಪ್ರಕ್ರಿಯೆಗೊಳಿಸುವಿಕೆ ರದ್ದುಗೊಂಡಿದೆ"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"ಮಾಧ್ಯಮ ಪ್ರಕ್ರಿಯೆಗೊಳಿಸುವಿಕೆ ದೋಷ"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"ಮಾಧ್ಯಮ ಪ್ರಕ್ರಿಯೆಗೊಳಿಸುವಿಕೆ ಯಶಸ್ವಿಯಾಗಿದೆ"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"ಮಾಧ್ಯಮ ಪ್ರಕ್ರಿಯೆಗೊಳಿಸುವಿಕೆ ಪ್ರಾರಂಭವಾಗಿದೆ"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"ಪ್ರಕ್ರಿಯೆಯಲ್ಲಿರುವ ಮಾಧ್ಯಮ…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"ರದ್ದುಮಾಡಿ"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"ನಿರೀಕ್ಷಿಸಿ"</string>
</resources>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 97fa4ec..afb14cc 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>에서 오디오 파일 <xliff:g id="COUNT">^2</xliff:g>개를 수정하도록 허용하시겠습니까?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>에서 이 오디오 파일을 수정하도록 허용하시겠습니까?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other">오디오 파일 <xliff:g id="COUNT">^1</xliff:g>개 수정 중…</item>
+ <item quantity="one">오디오 파일 수정 중…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>에서 동영상 <xliff:g id="COUNT">^2</xliff:g>개를 수정하도록 허용하시겠습니까?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>에서 이 동영상을 수정하도록 허용하시겠습니까?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other">동영상 <xliff:g id="COUNT">^1</xliff:g>개 수정 중…</item>
+ <item quantity="one">동영상 수정 중…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>에서 사진 <xliff:g id="COUNT">^2</xliff:g>개를 수정하도록 허용하시겠습니까?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>에서 이 사진을 수정하도록 허용하시겠습니까?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other">사진 <xliff:g id="COUNT">^1</xliff:g>개 수정 중…</item>
+ <item quantity="one">사진 수정 중…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>에서 항목 <xliff:g id="COUNT">^2</xliff:g>개를 수정하도록 허용하시겠습니까?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>에서 이 항목을 수정하도록 허용하시겠습니까?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other">항목 <xliff:g id="COUNT">^1</xliff:g>개 수정 중…</item>
+ <item quantity="one">항목 수정 중…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>에서 오디오 파일 <xliff:g id="COUNT">^2</xliff:g>개를 휴지통으로 이동하도록 허용하시겠습니까?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>에서 이 오디오 파일을 휴지통으로 이동하도록 허용하시겠습니까?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other">오디오 파일 <xliff:g id="COUNT">^1</xliff:g>개를 휴지통으로 이동하는 중…</item>
+ <item quantity="one">오디오 파일을 휴지통으로 이동하는 중…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>에서 동영상 <xliff:g id="COUNT">^2</xliff:g>개를 휴지통으로 이동하도록 허용하시겠습니까?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>에서 이 동영상을 휴지통으로 이동하도록 허용하시겠습니까?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other">동영상 <xliff:g id="COUNT">^1</xliff:g>개를 휴지통으로 이동하는 중…</item>
+ <item quantity="one">동영상을 휴지통으로 이동하는 중…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>에서 사진 <xliff:g id="COUNT">^2</xliff:g>개를 휴지통으로 이동하도록 허용하시겠습니까?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>에서 이 사진을 휴지통으로 이동하도록 허용하시겠습니까?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other">사진 <xliff:g id="COUNT">^1</xliff:g>개를 휴지통으로 이동하는 중…</item>
+ <item quantity="one">사진을 휴지통으로 이동하는 중…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>에서 항목 <xliff:g id="COUNT">^2</xliff:g>개를 휴지통으로 이동하도록 허용하시겠습니까?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>에서 이 항목을 휴지통으로 이동하도록 허용하시겠습니까?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other">항목 <xliff:g id="COUNT">^1</xliff:g>개를 휴지통으로 이동하는 중…</item>
+ <item quantity="one">항목을 휴지통으로 이동하는 중…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>에서 오디오 파일 <xliff:g id="COUNT">^2</xliff:g>개를 휴지통에서 꺼내도록 허용하시겠습니까?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>에서 이 오디오 파일을 휴지통에서 꺼내도록 허용하시겠습니까?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other">오디오 파일 <xliff:g id="COUNT">^1</xliff:g>개를 휴지통에서 꺼내는 중…</item>
+ <item quantity="one">오디오 파일을 휴지통에서 꺼내는 중…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>에서 동영상 <xliff:g id="COUNT">^2</xliff:g>개를 휴지통에서 꺼내도록 허용하시겠습니까?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>에서 이 동영상을 휴지통에서 꺼내도록 허용하시겠습니까?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other">동영상 <xliff:g id="COUNT">^1</xliff:g>개를 휴지통에서 꺼내는 중…</item>
+ <item quantity="one">동영상을 휴지통에서 꺼내는 중…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>에서 사진 <xliff:g id="COUNT">^2</xliff:g>개를 휴지통에서 꺼내도록 허용하시겠습니까?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>에서 이 사진을 휴지통에서 꺼내도록 허용하시겠습니까?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other">사진 <xliff:g id="COUNT">^1</xliff:g>개를 휴지통에서 꺼내는 중…</item>
+ <item quantity="one">사진을 휴지통에서 꺼내는 중…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>에서 항목 <xliff:g id="COUNT">^2</xliff:g>개를 휴지통에서 꺼내도록 허용하시겠습니까?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>에서 이 항목을 휴지통에서 꺼내도록 허용하시겠습니까?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other">항목 <xliff:g id="COUNT">^1</xliff:g>개를 휴지통에서 꺼내는 중…</item>
+ <item quantity="one">항목을 휴지통에서 꺼내는 중…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>에서 오디오 파일 <xliff:g id="COUNT">^2</xliff:g>개를 삭제하도록 허용하시겠습니까?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>에서 이 오디오 파일을 삭제하도록 허용하시겠습니까?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other">오디오 파일 <xliff:g id="COUNT">^1</xliff:g>개 삭제 중…</item>
+ <item quantity="one">오디오 파일 삭제 중…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>에서 동영상 <xliff:g id="COUNT">^2</xliff:g>개를 삭제하도록 허용하시겠습니까?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>에서 이 동영상을 삭제하도록 허용하시겠습니까?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other">동영상 <xliff:g id="COUNT">^1</xliff:g>개 삭제 중…</item>
+ <item quantity="one">동영상 삭제 중…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>에서 사진 <xliff:g id="COUNT">^2</xliff:g>개를 삭제하도록 허용하시겠습니까?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>에서 이 사진을 삭제하도록 허용하시겠습니까?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other">사진 <xliff:g id="COUNT">^1</xliff:g>개 삭제 중…</item>
+ <item quantity="one">사진 삭제 중…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>에서 항목 <xliff:g id="COUNT">^2</xliff:g>개를 삭제하도록 허용하시겠습니까?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>에서 이 항목을 삭제하도록 허용하시겠습니까?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other">항목 <xliff:g id="COUNT">^1</xliff:g>개 삭제 중…</item>
+ <item quantity="one">항목 삭제 중…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g>에서 미디어 파일을 처리할 수 없습니다"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"미디어 처리 취소됨"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"미디어 처리 오류"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"미디어 처리 성공"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"미디어 처리 시작됨"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"미디어 처리 중…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"취소"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"대기"</string>
</resources>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 5f065b6..f6b244b 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> колдонмосу <xliff:g id="COUNT">^2</xliff:g> аудио файлды өзгөртсүнбү?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> колдонмосу бул аудио файлды өзгөртсүнбү?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> аудио файл өзгөртүлүүдө…</item>
+ <item quantity="one">Аудио файл өзгөртүлүүдө…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> колдонмосу <xliff:g id="COUNT">^2</xliff:g> видеону өзгөртсүнбү?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> колдонмосу бул видеону өзгөртсүнбү?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> видео өзгөртүлүүдө…</item>
+ <item quantity="one">Видео өзгөртүлүүдө…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> колдонмосу <xliff:g id="COUNT">^2</xliff:g> сүрөттү өзгөртсүнбү?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> колдонмосу бул сүрөттү өзгөртсүнбү?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> сүрөт өзгөртүлүүдө…</item>
+ <item quantity="one">Сүрөт өзгөртүлүүдө…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> колдонмосу <xliff:g id="COUNT">^2</xliff:g> нерсени өзгөртсүнбү?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> колдонмосу бул нерсени өзгөртсүнбү?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> элемент өзгөртүлүүдө…</item>
+ <item quantity="one">Элемент өзгөртүлүүдө…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> колдонмосу <xliff:g id="COUNT">^2</xliff:g> аудио файлды таштандыга салсынбы?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> колдонмосу бул аудио файлды таштандыга салсынбы?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> аудио файл таштандыга ыргытылууда…</item>
+ <item quantity="one">Аудио файл таштандыга ыргытылууда…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> колдонмосу <xliff:g id="COUNT">^2</xliff:g> видеону таштандыга салсынбы?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> колдонмосу бул видеону таштандыга салсынбы?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> видео таштандыга ыргытылууда…</item>
+ <item quantity="one">Видео таштандыга ыргытылууда…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> <xliff:g id="COUNT">^2</xliff:g> сүрөттү таштандыга салсынбы?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> бул сүрөттү таштандыга салсынбы?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> сүрөт таштандыга ыргытылууда…</item>
+ <item quantity="one">Сүрөт таштандыга ыргытылууда…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> колдонмосу <xliff:g id="COUNT">^2</xliff:g> нерсени таштандыга салсынбы?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> колдонмосу бул нерсени таштандыга салсынбы?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> элемент таштандыга ыргытылууда…</item>
+ <item quantity="one">Элемент таштандыга ыргытылууда…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> колдонмосу <xliff:g id="COUNT">^2</xliff:g> аудио файлды калыбына келтирсинби?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> колдонмосу бул аудио файлды калыбына келтирсинби?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> аудио файл калыбына келтирилүүдө…</item>
+ <item quantity="one">Аудио файл калыбына келтирилүүдө…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> колдонмосу <xliff:g id="COUNT">^2</xliff:g> видеону калыбына келтирсинби?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> колдонмосу бул видеону калыбына келтирсинби?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> видео калыбына келтирилүүдө…</item>
+ <item quantity="one">Видео калыбына келтирилүүдө…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> колдонмосу <xliff:g id="COUNT">^2</xliff:g> сүрөттү калыбына келтирсинби?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> колдонмосу бул сүрөттү калыбына келтирсинби?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> сүрөт калыбына келтирилүүдө…</item>
+ <item quantity="one">Сүрөт калыбына келтирилүүдө…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> колдонмосу <xliff:g id="COUNT">^2</xliff:g> нерсени калыбына келтирсинби?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> колдонмосу бул нерсени калыбына келтирсинби?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> элемент калыбына келтирилүүдө…</item>
+ <item quantity="one">Элемент калыбына келтирилүүдө…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> колдонмосу <xliff:g id="COUNT">^2</xliff:g> аудио файлды өчүрсүнбү?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> колдонмосу бул аудио файлды өчүрсүнбү?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> аудио файл өчүрүлүүдө…</item>
+ <item quantity="one">Аудио файл өчүрүлүүдө…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> колдонмосу <xliff:g id="COUNT">^2</xliff:g> видеону өчүрсүнбү?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> колдонмосу бул видеону өчүрсүнбү?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> видео жок кылынууда…</item>
+ <item quantity="one">Видео жок кылынууда…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> колдонмосу <xliff:g id="COUNT">^2</xliff:g> сүрөттү өчүрсүнбү?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> колдонмосу бул сүрөттү өчүрсүнбү?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> сүрөт жок кылынууда…</item>
+ <item quantity="one">Сүрөт жок кылынууда…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> колдонмосу <xliff:g id="COUNT">^2</xliff:g> нерсени өчүрсүнбү?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> колдонмосу бул нерсени өчүрсүнбү?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> элемент жок кылынууда…</item>
+ <item quantity="one">Элемент жок кылынууда…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> медиа файлдарды иштете албайт"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Медианы иштетүү жокко чыгарылды"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Медианы иштетүү катасы"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Медиа ийгиликтүү иштетилди"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Медиа иштетилип баштады"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Медиа иштетилүүдө…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Жокко чыгаруу"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Күтүү"</string>
</resources>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index 568d20a..c21aec4 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_1">^1</xliff:g> ແກ້ໄຂໄຟລ໌ສຽງ <xliff:g id="COUNT">^2</xliff:g> ໄຟລ໌ບໍ?</item>
<item quantity="one">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_0">^1</xliff:g> ແກ້ໄຂໄຟລ໌ສຽງນີ້ບໍ?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other">ກຳລັງແກ້ໄຂໄຟລ໌ສຽງ <xliff:g id="COUNT">^1</xliff:g> ໄຟລ໌…</item>
+ <item quantity="one">ກຳລັງແກ້ໄຂໄຟລ໌ສຽງ…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_1">^1</xliff:g> ແກ້ໄຂ <xliff:g id="COUNT">^2</xliff:g> ວິດີໂອບໍ?</item>
<item quantity="one">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_0">^1</xliff:g> ແກ້ໄຂວິດີໂອນີ້ບໍ?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other">ກຳລັງແກ້ໄຂວິດີໂອ <xliff:g id="COUNT">^1</xliff:g> ອັນ…</item>
+ <item quantity="one">ກຳລັງແກ້ໄຂວິດີໂອ…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_1">^1</xliff:g> ແກ້ໄຂ <xliff:g id="COUNT">^2</xliff:g> ຮູບບໍ?</item>
<item quantity="one">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_0">^1</xliff:g> ແກ້ໄຂຮູບນີ້ບໍ?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other">ກຳລັງແກ້ໄຂຮູບພາບ <xliff:g id="COUNT">^1</xliff:g> ຮູບ…</item>
+ <item quantity="one">ກຳລັງແກ້ໄຂຮູບພາບ…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_1">^1</xliff:g> ແກ້ໄຂ <xliff:g id="COUNT">^2</xliff:g> ລາຍການບໍ?</item>
<item quantity="one">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_0">^1</xliff:g> ແກ້ໄຂລາຍການນີ້ບໍ?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other">ກຳລັງແກ້ໄຂລາຍການ <xliff:g id="COUNT">^1</xliff:g> ລາຍການ…</item>
+ <item quantity="one">ກຳລັງແກ້ໄຂລາຍການ…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_1">^1</xliff:g> ຍ້າຍໄຟລ໌ສຽງ <xliff:g id="COUNT">^2</xliff:g> ໄຟລ໌ໄປໃສ່ຖັງຂີ້ເຫຍື້ອບໍ?</item>
<item quantity="one">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_0">^1</xliff:g> ຍ້າຍໄຟລ໌ສຽງນີ້ໄປໃສ່ຖັງຂີ້ເຫຍື້ອບໍ?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other">ກຳລັງຍ້າຍໄຟລ໌ສຽງ <xliff:g id="COUNT">^1</xliff:g> ໄຟລ໌ໄປໃສ່ຖັງຂີ້ເຫຍື້ອ…</item>
+ <item quantity="one">ກຳລັງຍ້າຍໄຟລ໌ສຽງໄປໃສ່ຖັງຂີ້ເຫຍື້ອ…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_1">^1</xliff:g> ຍ້າຍ <xliff:g id="COUNT">^2</xliff:g> ວິດີໂອໄປໃສ່ຖັງຂີ້ເຫຍື້ອບໍ?</item>
<item quantity="one">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_0">^1</xliff:g> ຍ້າຍວິດີໂອນີ້ໄປໃສ່ຖັງຂີ້ເຫຍື້ອບໍ?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other">ກຳລັງຍ້າຍວິດີໂອ <xliff:g id="COUNT">^1</xliff:g> ອັນໄປໃສ່ຖັງຂີ້ເຫຍື້ອ…</item>
+ <item quantity="one">ກຳລັງຍ້າຍວິດີໂອໄປໃສ່ຖັງຂີ້ເຫຍື້ອ…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_1">^1</xliff:g> ຍ້າຍ <xliff:g id="COUNT">^2</xliff:g> ຮູບໄປໃສ່ຖັງຂີ້ເຫຍື້ອບໍ?</item>
<item quantity="one">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_0">^1</xliff:g> ຍ້າຍຮູບນີ້ໄປໃສ່ຖັງຂີ້ເຫຍື້ອບໍ?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other">ກຳລັງຍ້າຍຮູບພາບ <xliff:g id="COUNT">^1</xliff:g> ຮູບໄປໃສ່ຖັງຂີ້ເຫຍື້ອ…</item>
+ <item quantity="one">ກຳລັງຍ້າຍຮູບພາບໄປໃສ່ຖັງຂີ້ເຫຍື້ອ…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_1">^1</xliff:g> ຍ້າຍ <xliff:g id="COUNT">^2</xliff:g> ລາຍການໄປໃສ່ຖັງຂີ້ເຫຍື້ອບໍ?</item>
<item quantity="one">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_0">^1</xliff:g> ຍ້າຍລາຍການນີ້ໄປໃສ່ຖັງຂີ້ເຫຍື້ອບໍ?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other">ກຳລັງຍ້າຍລາຍການ <xliff:g id="COUNT">^1</xliff:g> ລາຍການໄປໃສ່ຖັງຂີ້ເຫຍື້ອ…</item>
+ <item quantity="one">ກຳລັງຍ້າຍລາຍການໄປໃສ່ຖັງຂີ້ເຫຍື້ອ…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_1">^1</xliff:g> ຍ້າຍ <xliff:g id="COUNT">^2</xliff:g> ໄຟລ໌ສຽງອອກຈາກຖັງຂີ້ເຫຍື້ອບໍ?</item>
<item quantity="one">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_0">^1</xliff:g> ຍ້າຍໄຟລ໌ສຽງນີ້ອອກຈາກຖັງຂີ້ເຫຍື້ອບໍ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other">ກຳລັງຍ້າຍໄຟລ໌ສຽງ <xliff:g id="COUNT">^1</xliff:g> ໄຟລ໌ອອກຈາກຖັງຂີ້ເຫຍື້ອ…</item>
+ <item quantity="one">ກຳລັງຍ້າຍໄຟລ໌ສຽງອອກຈາກຖັງຂີ້ເຫຍື້ອ…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_1">^1</xliff:g> ຍ້າຍ <xliff:g id="COUNT">^2</xliff:g> ວິດີໂອອອກຈາກຖັງຂີ້ເຫຍື້ອບໍ?</item>
<item quantity="one">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_0">^1</xliff:g> ຍ້າຍວິດີໂອນີ້ອອກຈາກຖັງຂີ້ເຫຍື້ອບໍ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other">ກຳລັງຍ້າຍວິດີໂອ <xliff:g id="COUNT">^1</xliff:g> ອັນອອກຈາກຖັງຂີ້ເຫຍື້ອ…</item>
+ <item quantity="one">ກຳລັງຍ້າຍວິດີໂອອອກຈາກຖັງຂີ້ເຫຍື້ອ…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_1">^1</xliff:g> ຍ້າຍ <xliff:g id="COUNT">^2</xliff:g> ຮູບອອກຈາກຖັງຂີ້ເຫຍື້ອບໍ?</item>
<item quantity="one">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_0">^1</xliff:g> ຍ້າຍຮູບນີ້ອອກຈາກຖັງຂີ້ເຫຍື້ອບໍ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other">ກຳລັງຍ້າຍຮູບພາບ <xliff:g id="COUNT">^1</xliff:g> ຮູບອອກຈາກຖັງຂີ້ເຫຍື້ອ…</item>
+ <item quantity="one">ກຳລັງຍ້າຍຮູບພາບອອກຈາກຖັງຂີ້ເຫຍື້ອ…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_1">^1</xliff:g> ຍ້າຍ <xliff:g id="COUNT">^2</xliff:g> ລາຍການອອກຈາກຖັງຂີ້ເຫຍື້ອບໍ?</item>
<item quantity="one">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_0">^1</xliff:g> ຍ້າຍລາຍການນີ້ອອກຈາກຖັງຂີ້ເຫຍື້ອບໍ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other">ກຳລັງຍ້າຍລາຍການ <xliff:g id="COUNT">^1</xliff:g> ລາຍການອອກຈາກຖັງຂີ້ເຫຍື້ອ…</item>
+ <item quantity="one">ກຳລັງຍ້າຍລາຍການອອກຈາກຖັງຂີ້ເຫຍື້ອ…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_1">^1</xliff:g> ລຶບໄຟລ໌ສຽງ <xliff:g id="COUNT">^2</xliff:g> ໄຟລ໌ບໍ?</item>
<item quantity="one">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_0">^1</xliff:g> ລຶບໄຟລ໌ສຽງນີ້ບໍ?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other">ກຳລັງລຶບໄຟລ໌ສຽງ <xliff:g id="COUNT">^1</xliff:g> ໄຟລ໌ອອກ…</item>
+ <item quantity="one">ກຳລັງລຶບໄຟລ໌ສຽງອອກ…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_1">^1</xliff:g> ລຶບ <xliff:g id="COUNT">^2</xliff:g> ວິດີໂອບໍ?</item>
<item quantity="one">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_0">^1</xliff:g> ລຶບວິດີໂອນີ້ບໍ?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other">ກຳລັງລຶບວິດີໂອ <xliff:g id="COUNT">^1</xliff:g> ອັນອອກ…</item>
+ <item quantity="one">ກຳລັງລຶບວິດີໂອ…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_1">^1</xliff:g> ລຶບ <xliff:g id="COUNT">^2</xliff:g> ຮູບບໍ?</item>
<item quantity="one">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_0">^1</xliff:g> ລຶບຮູບນີ້ບໍ?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other">ກຳລັງລຶບຮູບພາບ <xliff:g id="COUNT">^1</xliff:g> ຮູບອອກ…</item>
+ <item quantity="one">ກຳລັງລຶບຮູບພາບ…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_1">^1</xliff:g> ລຶບ <xliff:g id="COUNT">^2</xliff:g> ລາຍການບໍ?</item>
<item quantity="one">ອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME_0">^1</xliff:g> ລຶບລາຍການນີ້ບໍ?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other">ກຳລັງລຶບລາຍການ <xliff:g id="COUNT">^1</xliff:g> ລາຍການອອກ…</item>
+ <item quantity="one">ກຳລັງລຶບລາຍການອອກ…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> ບໍ່ສາມາດປະມວນຜົນໄຟລ໌ມີເດຍໄດ້"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"ຍົກເລີກການປະມວນຜົນມີເດຍແລ້ວ"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"ການປະມວນຜົນມີເດຍຜິດພາດ"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"ການປະມວນຜົນມີເດຍສຳເລັດແລ້ວ"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"ເລີ່ມການປະມວນຜົນມີເດຍແລ້ວ"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"ກຳລັງປະມວນຜົນມີເດຍ…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"ຍົກເລີກ"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"ລໍຖ້າ"</string>
</resources>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 4190c0f..c4f30d9 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -53,94 +53,198 @@
<item quantity="many">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ keisti <xliff:g id="COUNT">^2</xliff:g> garso failo?</item>
<item quantity="other">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ keisti <xliff:g id="COUNT">^2</xliff:g> garso failų?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="one">Keičiamas <xliff:g id="COUNT">^1</xliff:g> garso failas…</item>
+ <item quantity="few">Keičiami <xliff:g id="COUNT">^1</xliff:g> garso failai…</item>
+ <item quantity="many">Keičiama <xliff:g id="COUNT">^1</xliff:g> garso failo…</item>
+ <item quantity="other">Keičiama <xliff:g id="COUNT">^1</xliff:g> garso failų…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="one">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ keisti <xliff:g id="COUNT">^2</xliff:g> vaizdo įrašą?</item>
<item quantity="few">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ keisti <xliff:g id="COUNT">^2</xliff:g> vaizdo įrašus?</item>
<item quantity="many">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ keisti <xliff:g id="COUNT">^2</xliff:g> vaizdo įrašo?</item>
<item quantity="other">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ keisti <xliff:g id="COUNT">^2</xliff:g> vaizdo įrašų?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="one">Keičiamas <xliff:g id="COUNT">^1</xliff:g> vaizdo įrašas…</item>
+ <item quantity="few">Keičiami <xliff:g id="COUNT">^1</xliff:g> vaizdo įrašai…</item>
+ <item quantity="many">Keičiama <xliff:g id="COUNT">^1</xliff:g> vaizdo įrašo…</item>
+ <item quantity="other">Keičiama <xliff:g id="COUNT">^1</xliff:g> vaizdo įrašų…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="one">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ keisti <xliff:g id="COUNT">^2</xliff:g> nuotrauką?</item>
<item quantity="few">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ keisti <xliff:g id="COUNT">^2</xliff:g> nuotraukas?</item>
<item quantity="many">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ keisti <xliff:g id="COUNT">^2</xliff:g> nuotraukos?</item>
<item quantity="other">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ keisti <xliff:g id="COUNT">^2</xliff:g> nuotraukų?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="one">Keičiama <xliff:g id="COUNT">^1</xliff:g> nuotrauka…</item>
+ <item quantity="few">Keičiamos <xliff:g id="COUNT">^1</xliff:g> nuotraukos…</item>
+ <item quantity="many">Keičiama <xliff:g id="COUNT">^1</xliff:g> nuotraukos…</item>
+ <item quantity="other">Keičiama <xliff:g id="COUNT">^1</xliff:g> nuotraukų…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="one">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ keisti <xliff:g id="COUNT">^2</xliff:g> elementą?</item>
<item quantity="few">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ keisti <xliff:g id="COUNT">^2</xliff:g> elementus?</item>
<item quantity="many">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ keisti <xliff:g id="COUNT">^2</xliff:g> elemento?</item>
<item quantity="other">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ keisti <xliff:g id="COUNT">^2</xliff:g> elementų?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="one">Keičiamas <xliff:g id="COUNT">^1</xliff:g> elementas…</item>
+ <item quantity="few">Keičiami <xliff:g id="COUNT">^1</xliff:g> elementai…</item>
+ <item quantity="many">Keičiama <xliff:g id="COUNT">^1</xliff:g> elemento…</item>
+ <item quantity="other">Keičiama <xliff:g id="COUNT">^1</xliff:g> elementų…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="one">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> garso failą į šiukšliadėžę?</item>
<item quantity="few">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> garso failus į šiukšliadėžę?</item>
<item quantity="many">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> garso failo į šiukšliadėžę?</item>
<item quantity="other">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> garso failų į šiukšliadėžę?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="one">Perkeliamas <xliff:g id="COUNT">^1</xliff:g> garso failas į šiukšliadėžę…</item>
+ <item quantity="few">Perkeliami <xliff:g id="COUNT">^1</xliff:g> garso failai į šiukšliadėžę…</item>
+ <item quantity="many">Perkeliama <xliff:g id="COUNT">^1</xliff:g> garso failo į šiukšliadėžę…</item>
+ <item quantity="other">Perkeliama <xliff:g id="COUNT">^1</xliff:g> garso failų į šiukšliadėžę…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="one">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> vaizdo įrašą į šiukšliadėžę?</item>
<item quantity="few">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> vaizdo įrašus į šiukšliadėžę?</item>
<item quantity="many">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> vaizdo įrašo į šiukšliadėžę?</item>
<item quantity="other">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> vaizdo įrašų į šiukšliadėžę?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="one">Perkeliamas <xliff:g id="COUNT">^1</xliff:g> vaizdo įrašas į šiukšliadėžę…</item>
+ <item quantity="few">Perkeliami <xliff:g id="COUNT">^1</xliff:g> vaizdo įrašai į šiukšliadėžę…</item>
+ <item quantity="many">Perkeliama <xliff:g id="COUNT">^1</xliff:g> vaizdo įrašo į šiukšliadėžę…</item>
+ <item quantity="other">Perkeliama <xliff:g id="COUNT">^1</xliff:g> vaizdo įrašų į šiukšliadėžę…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="one">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> nuotrauką į šiukšliadėžę?</item>
<item quantity="few">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> nuotraukas į šiukšliadėžę?</item>
<item quantity="many">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> nuotraukos į šiukšliadėžę?</item>
<item quantity="other">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> nuotraukų į šiukšliadėžę?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="one">Perkeliama <xliff:g id="COUNT">^1</xliff:g> nuotrauka į šiukšliadėžę…</item>
+ <item quantity="few">Perkeliamos <xliff:g id="COUNT">^1</xliff:g> nuotraukos į šiukšliadėžę…</item>
+ <item quantity="many">Perkeliama <xliff:g id="COUNT">^1</xliff:g> nuotraukos į šiukšliadėžę…</item>
+ <item quantity="other">Perkeliama <xliff:g id="COUNT">^1</xliff:g> nuotraukų į šiukšliadėžę…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="one">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> elementą į šiukšliadėžę?</item>
<item quantity="few">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> elementus į šiukšliadėžę?</item>
<item quantity="many">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> elemento į šiukšliadėžę?</item>
<item quantity="other">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> elementų į šiukšliadėžę?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="one">Perkeliamas <xliff:g id="COUNT">^1</xliff:g> elementas į šiukšliadėžę…</item>
+ <item quantity="few">Perkeliami <xliff:g id="COUNT">^1</xliff:g> elementai į šiukšliadėžę…</item>
+ <item quantity="many">Perkeliama <xliff:g id="COUNT">^1</xliff:g> elemento į šiukšliadėžę…</item>
+ <item quantity="other">Perkeliama <xliff:g id="COUNT">^1</xliff:g> elementų į šiukšliadėžę…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="one">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> garso failą iš šiukšliadėžės?</item>
<item quantity="few">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> garso failus iš šiukšliadėžės?</item>
<item quantity="many">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> garso failo iš šiukšliadėžės?</item>
<item quantity="other">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> garso failų iš šiukšliadėžės?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="one">Perkeliamas <xliff:g id="COUNT">^1</xliff:g> garso failas iš šiukšliadėžės…</item>
+ <item quantity="few">Perkeliami <xliff:g id="COUNT">^1</xliff:g> garso failai iš šiukšliadėžės…</item>
+ <item quantity="many">Perkeliama <xliff:g id="COUNT">^1</xliff:g> garso failo iš šiukšliadėžės…</item>
+ <item quantity="other">Perkeliama <xliff:g id="COUNT">^1</xliff:g> garso failų iš šiukšliadėžės…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="one">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> vaizdo įrašą iš šiukšliadėžės?</item>
<item quantity="few">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> vaizdo įrašus iš šiukšliadėžės?</item>
<item quantity="many">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> vaizdo įrašo iš šiukšliadėžės?</item>
<item quantity="other">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> vaizdo įrašų iš šiukšliadėžės?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="one">Perkeliamas <xliff:g id="COUNT">^1</xliff:g> vaizdo įrašas iš šiukšliadėžės…</item>
+ <item quantity="few">Perkeliami <xliff:g id="COUNT">^1</xliff:g> vaizdo įrašai iš šiukšliadėžės…</item>
+ <item quantity="many">Perkeliama <xliff:g id="COUNT">^1</xliff:g> vaizdo įrašo iš šiukšliadėžės…</item>
+ <item quantity="other">Perkeliama <xliff:g id="COUNT">^1</xliff:g> vaizdo įrašų iš šiukšliadėžės…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="one">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> nuotrauką iš šiukšliadėžės?</item>
<item quantity="few">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> nuotraukas iš šiukšliadėžės?</item>
<item quantity="many">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> nuotraukos iš šiukšliadėžės?</item>
<item quantity="other">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> nuotraukų iš šiukšliadėžės?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="one">Perkeliama <xliff:g id="COUNT">^1</xliff:g> nuotrauka iš šiukšliadėžės…</item>
+ <item quantity="few">Perkeliamos <xliff:g id="COUNT">^1</xliff:g> nuotraukos iš šiukšliadėžės…</item>
+ <item quantity="many">Perkeliama <xliff:g id="COUNT">^1</xliff:g> nuotraukos iš šiukšliadėžės…</item>
+ <item quantity="other">Perkeliama <xliff:g id="COUNT">^1</xliff:g> nuotraukų iš šiukšliadėžės…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="one">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> elementą iš šiukšliadėžės?</item>
<item quantity="few">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> elementus iš šiukšliadėžės?</item>
<item quantity="many">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> elemento iš šiukšliadėžės?</item>
<item quantity="other">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ perkelti <xliff:g id="COUNT">^2</xliff:g> elementų iš šiukšliadėžės?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="one">Perkeliamas <xliff:g id="COUNT">^1</xliff:g> elementas iš šiukšliadėžės…</item>
+ <item quantity="few">Perkeliami <xliff:g id="COUNT">^1</xliff:g> elementai iš šiukšliadėžės…</item>
+ <item quantity="many">Perkeliama <xliff:g id="COUNT">^1</xliff:g> elemento iš šiukšliadėžės…</item>
+ <item quantity="other">Perkeliama <xliff:g id="COUNT">^1</xliff:g> elementų iš šiukšliadėžės…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="one">Leisti „<xliff:g id="APP_NAME_1">^1</xliff:g>“ ištrinti <xliff:g id="COUNT">^2</xliff:g> garso failą?</item>
<item quantity="few">Leisti „<xliff:g id="APP_NAME_1">^1</xliff:g>“ ištrinti <xliff:g id="COUNT">^2</xliff:g> garso failus?</item>
<item quantity="many">Leisti „<xliff:g id="APP_NAME_1">^1</xliff:g>“ ištrinti <xliff:g id="COUNT">^2</xliff:g> garso failo?</item>
<item quantity="other">Leisti „<xliff:g id="APP_NAME_1">^1</xliff:g>“ ištrinti <xliff:g id="COUNT">^2</xliff:g> garso failų?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="one">Ištrinamas <xliff:g id="COUNT">^1</xliff:g> garso failas…</item>
+ <item quantity="few">Ištrinami <xliff:g id="COUNT">^1</xliff:g> garso failai…</item>
+ <item quantity="many">Ištrinama <xliff:g id="COUNT">^1</xliff:g> garso failo…</item>
+ <item quantity="other">Ištrinama <xliff:g id="COUNT">^1</xliff:g> garso failų…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="one">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ ištrinti <xliff:g id="COUNT">^2</xliff:g> vaizdo įrašą?</item>
<item quantity="few">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ ištrinti <xliff:g id="COUNT">^2</xliff:g> vaizdo įrašus?</item>
<item quantity="many">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ ištrinti <xliff:g id="COUNT">^2</xliff:g> vaizdo įrašo?</item>
<item quantity="other">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ ištrinti <xliff:g id="COUNT">^2</xliff:g> vaizdo įrašų?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="one">Ištrinamas <xliff:g id="COUNT">^1</xliff:g> vaizdo įrašas…</item>
+ <item quantity="few">Ištrinami <xliff:g id="COUNT">^1</xliff:g> vaizdo įrašai…</item>
+ <item quantity="many">Ištrinama <xliff:g id="COUNT">^1</xliff:g> vaizdo įrašo…</item>
+ <item quantity="other">Ištrinama <xliff:g id="COUNT">^1</xliff:g> vaizdo įrašų…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="one">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ ištrinti <xliff:g id="COUNT">^2</xliff:g> nuotrauką?</item>
<item quantity="few">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ ištrinti <xliff:g id="COUNT">^2</xliff:g> nuotraukas?</item>
<item quantity="many">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ ištrinti <xliff:g id="COUNT">^2</xliff:g> nuotraukos?</item>
<item quantity="other">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ ištrinti <xliff:g id="COUNT">^2</xliff:g> nuotraukų?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="one">Ištrinama <xliff:g id="COUNT">^1</xliff:g> nuotrauka…</item>
+ <item quantity="few">Ištrinamos <xliff:g id="COUNT">^1</xliff:g> nuotraukos…</item>
+ <item quantity="many">Ištrinama <xliff:g id="COUNT">^1</xliff:g> nuotraukos…</item>
+ <item quantity="other">Ištrinama <xliff:g id="COUNT">^1</xliff:g> nuotraukų…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="one">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ ištrinti <xliff:g id="COUNT">^2</xliff:g> elementą?</item>
<item quantity="few">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ ištrinti <xliff:g id="COUNT">^2</xliff:g> elementus?</item>
<item quantity="many">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ ištrinti <xliff:g id="COUNT">^2</xliff:g> elemento?</item>
<item quantity="other">Leisti programai „<xliff:g id="APP_NAME_1">^1</xliff:g>“ ištrinti <xliff:g id="COUNT">^2</xliff:g> elementų?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="one">Ištrinamas <xliff:g id="COUNT">^1</xliff:g> elementas…</item>
+ <item quantity="few">Ištrinami <xliff:g id="COUNT">^1</xliff:g> elementai…</item>
+ <item quantity="many">Ištrinama <xliff:g id="COUNT">^1</xliff:g> elemento…</item>
+ <item quantity="other">Ištrinama <xliff:g id="COUNT">^1</xliff:g> elementų…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"Programa „<xliff:g id="APP_NAME">%s</xliff:g>“ negali apdoroti medijos failų"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Medija apdorojimas atšauktas"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Medija apdorojimo klaida"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Medija apdorojimas sėkmingas"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Pradedama apdoroti mediją"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Medija apdorojama…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Atšaukti"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Palaukti"</string>
</resources>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 7bc296f..fbd2cba 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -50,79 +50,167 @@
<item quantity="one">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> modificēt <xliff:g id="COUNT">^2</xliff:g> audio failu?</item>
<item quantity="other">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> modificēt <xliff:g id="COUNT">^2</xliff:g> audio failus?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="zero">Notiek <xliff:g id="COUNT">^1</xliff:g> audio failu pārveidošana…</item>
+ <item quantity="one">Notiek <xliff:g id="COUNT">^1</xliff:g> audio faila pārveidošana…</item>
+ <item quantity="other">Notiek <xliff:g id="COUNT">^1</xliff:g> audio failu pārveidošana…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="zero">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> modificēt <xliff:g id="COUNT">^2</xliff:g> videoklipus?</item>
<item quantity="one">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> modificēt <xliff:g id="COUNT">^2</xliff:g> videoklipu?</item>
<item quantity="other">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> modificēt <xliff:g id="COUNT">^2</xliff:g> videoklipus?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="zero">Notiek <xliff:g id="COUNT">^1</xliff:g> videoklipu pārveidošana…</item>
+ <item quantity="one">Notiek <xliff:g id="COUNT">^1</xliff:g> videoklipa pārveidošana…</item>
+ <item quantity="other">Notiek <xliff:g id="COUNT">^1</xliff:g> videoklipu pārveidošana…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="zero">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> modificēt <xliff:g id="COUNT">^2</xliff:g> fotoattēlus?</item>
<item quantity="one">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> modificēt <xliff:g id="COUNT">^2</xliff:g> fotoattēlu?</item>
<item quantity="other">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> modificēt <xliff:g id="COUNT">^2</xliff:g> fotoattēlus?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="zero">Notiek <xliff:g id="COUNT">^1</xliff:g> fotoattēlu pārveidošana…</item>
+ <item quantity="one">Notiek <xliff:g id="COUNT">^1</xliff:g> fotoattēla pārveidošana…</item>
+ <item quantity="other">Notiek <xliff:g id="COUNT">^1</xliff:g> fotoattēlu pārveidošana…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="zero">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> modificēt <xliff:g id="COUNT">^2</xliff:g> vienumus?</item>
<item quantity="one">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> modificēt <xliff:g id="COUNT">^2</xliff:g> vienumu?</item>
<item quantity="other">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> modificēt <xliff:g id="COUNT">^2</xliff:g> vienumus?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="zero">Notiek <xliff:g id="COUNT">^1</xliff:g> vienumu pārveidošana…</item>
+ <item quantity="one">Notiek <xliff:g id="COUNT">^1</xliff:g> vienuma pārveidošana…</item>
+ <item quantity="other">Notiek <xliff:g id="COUNT">^1</xliff:g> vienumu pārveidošana…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="zero">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> pārvietot <xliff:g id="COUNT">^2</xliff:g> audio failus uz atkritni?</item>
<item quantity="one">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> pārvietot <xliff:g id="COUNT">^2</xliff:g> audio failu uz atkritni?</item>
<item quantity="other">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> pārvietot <xliff:g id="COUNT">^2</xliff:g> audio failus uz atkritni?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="zero">Notiek <xliff:g id="COUNT">^1</xliff:g> audio failu pārvietošana uz atkritni…</item>
+ <item quantity="one">Notiek <xliff:g id="COUNT">^1</xliff:g> audio faila pārvietošana uz atkritni…</item>
+ <item quantity="other">Notiek <xliff:g id="COUNT">^1</xliff:g> audio failu pārvietošana uz atkritni…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="zero">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> pārvietot <xliff:g id="COUNT">^2</xliff:g> videoklipus uz atkritni?</item>
<item quantity="one">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> pārvietot <xliff:g id="COUNT">^2</xliff:g> videoklipu uz atkritni?</item>
<item quantity="other">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> pārvietot <xliff:g id="COUNT">^2</xliff:g> videoklipus uz atkritni?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="zero">Notiek <xliff:g id="COUNT">^1</xliff:g> videoklipu pārvietošana uz atkritni…</item>
+ <item quantity="one">Notiek <xliff:g id="COUNT">^1</xliff:g> videoklipa pārvietošana uz atkritni…</item>
+ <item quantity="other">Notiek <xliff:g id="COUNT">^1</xliff:g> videoklipu pārvietošana uz atkritni…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="zero">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> pārvietot <xliff:g id="COUNT">^2</xliff:g> fotoattēlus uz atkritni?</item>
<item quantity="one">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> pārvietot <xliff:g id="COUNT">^2</xliff:g> fotoattēlu uz atkritni?</item>
<item quantity="other">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> pārvietot <xliff:g id="COUNT">^2</xliff:g> fotoattēlus uz atkritni?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="zero">Notiek <xliff:g id="COUNT">^1</xliff:g> fotoattēlu pārvietošana uz atkritni…</item>
+ <item quantity="one">Notiek <xliff:g id="COUNT">^1</xliff:g> fotoattēla pārvietošana uz atkritni…</item>
+ <item quantity="other">Notiek <xliff:g id="COUNT">^1</xliff:g> fotoattēlu pārvietošana uz atkritni…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="zero">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> pārvietot <xliff:g id="COUNT">^2</xliff:g> vienumus uz atkritni?</item>
<item quantity="one">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> pārvietot <xliff:g id="COUNT">^2</xliff:g> vienumu uz atkritni?</item>
<item quantity="other">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> pārvietot <xliff:g id="COUNT">^2</xliff:g> vienumus uz atkritni?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="zero">Notiek <xliff:g id="COUNT">^1</xliff:g> vienumu pārvietošana uz atkritni…</item>
+ <item quantity="one">Notiek <xliff:g id="COUNT">^1</xliff:g> vienuma pārvietošana uz atkritni…</item>
+ <item quantity="other">Notiek <xliff:g id="COUNT">^1</xliff:g> vienumu pārvietošana uz atkritni…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="zero">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> izņemt <xliff:g id="COUNT">^2</xliff:g> audio failus no atkritnes?</item>
<item quantity="one">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> izņemt <xliff:g id="COUNT">^2</xliff:g> audio failu no atkritnes?</item>
<item quantity="other">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> izņemt <xliff:g id="COUNT">^2</xliff:g> audio failus no atkritnes?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="zero">Notiek <xliff:g id="COUNT">^1</xliff:g> audio failu izņemšana no atkritnes…</item>
+ <item quantity="one">Notiek <xliff:g id="COUNT">^1</xliff:g> audio faila izņemšana no atkritnes…</item>
+ <item quantity="other">Notiek <xliff:g id="COUNT">^1</xliff:g> audio failu izņemšana no atkritnes…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="zero">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> izņemt <xliff:g id="COUNT">^2</xliff:g> videoklipus no atkritnes?</item>
<item quantity="one">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> izņemt <xliff:g id="COUNT">^2</xliff:g> videoklipu no atkritnes?</item>
<item quantity="other">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> izņemt <xliff:g id="COUNT">^2</xliff:g> videoklipus no atkritnes?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="zero">Notiek <xliff:g id="COUNT">^1</xliff:g> videoklipu izņemšana no atkritnes…</item>
+ <item quantity="one">Notiek <xliff:g id="COUNT">^1</xliff:g> videoklipa izņemšana no atkritnes…</item>
+ <item quantity="other">Notiek <xliff:g id="COUNT">^1</xliff:g> videoklipu izņemšana no atkritnes…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="zero">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> izņemt <xliff:g id="COUNT">^2</xliff:g> fotoattēlus no atkritnes?</item>
<item quantity="one">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> izņemt <xliff:g id="COUNT">^2</xliff:g> fotoattēlu no atkritnes?</item>
<item quantity="other">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> izņemt <xliff:g id="COUNT">^2</xliff:g> fotoattēlus no atkritnes?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="zero">Notiek <xliff:g id="COUNT">^1</xliff:g> fotoattēlu izņemšana no atkritnes…</item>
+ <item quantity="one">Notiek <xliff:g id="COUNT">^1</xliff:g> fotoattēla izņemšana no atkritnes…</item>
+ <item quantity="other">Notiek <xliff:g id="COUNT">^1</xliff:g> fotoattēlu izņemšana no atkritnes…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="zero">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> izņemt <xliff:g id="COUNT">^2</xliff:g> vienumus no atkritnes?</item>
<item quantity="one">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> izņemt <xliff:g id="COUNT">^2</xliff:g> vienumu no atkritnes?</item>
<item quantity="other">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> izņemt <xliff:g id="COUNT">^2</xliff:g> vienumus no atkritnes?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="zero">Notiek <xliff:g id="COUNT">^1</xliff:g> vienumu izņemšana no atkritnes…</item>
+ <item quantity="one">Notiek <xliff:g id="COUNT">^1</xliff:g> vienuma izņemšana no atkritnes…</item>
+ <item quantity="other">Notiek <xliff:g id="COUNT">^1</xliff:g> vienumu izņemšana no atkritnes…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="zero">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> dzēst <xliff:g id="COUNT">^2</xliff:g> audio failus?</item>
<item quantity="one">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> dzēst <xliff:g id="COUNT">^2</xliff:g> audio failu?</item>
<item quantity="other">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> dzēst <xliff:g id="COUNT">^2</xliff:g> audio failus?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="zero">Notiek <xliff:g id="COUNT">^1</xliff:g> audio failu dzēšana…</item>
+ <item quantity="one">Notiek <xliff:g id="COUNT">^1</xliff:g> audio faila dzēšana…</item>
+ <item quantity="other">Notiek <xliff:g id="COUNT">^1</xliff:g> audio failu dzēšana…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="zero">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> dzēst <xliff:g id="COUNT">^2</xliff:g> videoklipus?</item>
<item quantity="one">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> dzēst <xliff:g id="COUNT">^2</xliff:g> videoklipu?</item>
<item quantity="other">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> dzēst <xliff:g id="COUNT">^2</xliff:g> videoklipus?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="zero">Notiek <xliff:g id="COUNT">^1</xliff:g> videoklipu dzēšana…</item>
+ <item quantity="one">Notiek <xliff:g id="COUNT">^1</xliff:g> videoklipa dzēšana…</item>
+ <item quantity="other">Notiek <xliff:g id="COUNT">^1</xliff:g> videoklipu dzēšana…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="zero">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> dzēst <xliff:g id="COUNT">^2</xliff:g> fotoattēlus?</item>
<item quantity="one">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> dzēst <xliff:g id="COUNT">^2</xliff:g> fotoattēlu?</item>
<item quantity="other">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> dzēst <xliff:g id="COUNT">^2</xliff:g> fotoattēlus?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="zero">Notiek <xliff:g id="COUNT">^1</xliff:g> fotoattēlu dzēšana…</item>
+ <item quantity="one">Notiek <xliff:g id="COUNT">^1</xliff:g> fotoattēla dzēšana…</item>
+ <item quantity="other">Notiek <xliff:g id="COUNT">^1</xliff:g> fotoattēlu dzēšana…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="zero">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> dzēst <xliff:g id="COUNT">^2</xliff:g> vienumus?</item>
<item quantity="one">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> dzēst <xliff:g id="COUNT">^2</xliff:g> vienumu?</item>
<item quantity="other">Vai atļaut lietotnei <xliff:g id="APP_NAME_1">^1</xliff:g> dzēst <xliff:g id="COUNT">^2</xliff:g> vienumus?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="zero">Notiek <xliff:g id="COUNT">^1</xliff:g> vienumu dzēšana…</item>
+ <item quantity="one">Notiek <xliff:g id="COUNT">^1</xliff:g> vienuma dzēšana…</item>
+ <item quantity="other">Notiek <xliff:g id="COUNT">^1</xliff:g> vienumu dzēšana…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> nevar apstrādāt multivides failus"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Multivides apstrāde ir atcelta."</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Radās multivides apstrādes kļūda."</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Multivides apstrāde bija sekmīga."</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Tika sākta multivides apstrāde."</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Notiek multivides apstrāde…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Atcelt"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Gaidīt"</string>
</resources>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 2fe7609..3fad90a 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -47,64 +47,136 @@
<item quantity="one">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да измени <xliff:g id="COUNT">^2</xliff:g> аудиодатотека?</item>
<item quantity="other">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да измени <xliff:g id="COUNT">^2</xliff:g> аудиодатотеки?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="one">Се изменува <xliff:g id="COUNT">^1</xliff:g> аудиодатотека…</item>
+ <item quantity="other">Се изменуваат <xliff:g id="COUNT">^1</xliff:g> аудиодатотеки…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="one">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да измени <xliff:g id="COUNT">^2</xliff:g> видео?</item>
<item quantity="other">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да измени <xliff:g id="COUNT">^2</xliff:g> видеа?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="one">Се изменува <xliff:g id="COUNT">^1</xliff:g> видео…</item>
+ <item quantity="other">Се изменуваат <xliff:g id="COUNT">^1</xliff:g> видеа…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="one">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да измени <xliff:g id="COUNT">^2</xliff:g> фотографија?</item>
<item quantity="other">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да измени <xliff:g id="COUNT">^2</xliff:g> фотографии?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="one">Се изменува <xliff:g id="COUNT">^1</xliff:g> фотографија…</item>
+ <item quantity="other">Се изменуваат <xliff:g id="COUNT">^1</xliff:g> фотографии…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="one">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да измени <xliff:g id="COUNT">^2</xliff:g> ставка?</item>
<item quantity="other">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да измени <xliff:g id="COUNT">^2</xliff:g> ставки?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="one">Се изменува <xliff:g id="COUNT">^1</xliff:g> ставка…</item>
+ <item quantity="other">Се изменуваат <xliff:g id="COUNT">^1</xliff:g> ставки…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="one">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да премести <xliff:g id="COUNT">^2</xliff:g> аудиодатотека во корпата?</item>
<item quantity="other">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да премести <xliff:g id="COUNT">^2</xliff:g> аудиодатотеки во корпата?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="one">Се преместува <xliff:g id="COUNT">^1</xliff:g> аудиодатотека во корпата…</item>
+ <item quantity="other">Се преместуваат <xliff:g id="COUNT">^1</xliff:g> аудиодатотеки во корпата…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="one">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да премести <xliff:g id="COUNT">^2</xliff:g> видео во корпата?</item>
<item quantity="other">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да премести <xliff:g id="COUNT">^2</xliff:g> видеа во корпата?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="one">Се преместува <xliff:g id="COUNT">^1</xliff:g> видео во корпата…</item>
+ <item quantity="other">Се преместуваат <xliff:g id="COUNT">^1</xliff:g> видеа во корпата…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="one">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да премести <xliff:g id="COUNT">^2</xliff:g> фотографија во корпата?</item>
<item quantity="other">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да премести <xliff:g id="COUNT">^2</xliff:g> фотографии во корпата?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="one">Се преместува <xliff:g id="COUNT">^1</xliff:g> фотографија во корпата…</item>
+ <item quantity="other">Се преместуваат <xliff:g id="COUNT">^1</xliff:g> фотографии во корпата…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="one">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да премести <xliff:g id="COUNT">^2</xliff:g> ставка во корпата?</item>
<item quantity="other">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да премести <xliff:g id="COUNT">^2</xliff:g> ставки во корпата?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="one">Се преместува <xliff:g id="COUNT">^1</xliff:g> во корпата…</item>
+ <item quantity="other">Се преместуваат <xliff:g id="COUNT">^1</xliff:g> ставки во корпата…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="one">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да извади <xliff:g id="COUNT">^2</xliff:g> аудиодатотека од корпата?</item>
<item quantity="other">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да извади <xliff:g id="COUNT">^2</xliff:g> аудиодатотеки од корпата?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="one">Се вади <xliff:g id="COUNT">^1</xliff:g> аудиодатотека од корпата…</item>
+ <item quantity="other">Се вадат <xliff:g id="COUNT">^1</xliff:g> аудиодатотеки од корпата…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="one">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да извади <xliff:g id="COUNT">^2</xliff:g> видео од корпата?</item>
<item quantity="other">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да извади <xliff:g id="COUNT">^2</xliff:g> видеа од корпата?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="one">Се вади <xliff:g id="COUNT">^1</xliff:g> видео од корпата…</item>
+ <item quantity="other">Се вадат <xliff:g id="COUNT">^1</xliff:g> видеа од корпата…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="one">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да извади <xliff:g id="COUNT">^2</xliff:g> фотографија од корпата?</item>
<item quantity="other">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да извади <xliff:g id="COUNT">^2</xliff:g> фотографии од корпата?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="one">Се вади <xliff:g id="COUNT">^1</xliff:g> фотографија од корпата…</item>
+ <item quantity="other">Се вадат <xliff:g id="COUNT">^1</xliff:g> фотографии од корпата…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="one">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да извади <xliff:g id="COUNT">^2</xliff:g> ставка од корпата?</item>
<item quantity="other">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да извади <xliff:g id="COUNT">^2</xliff:g> ставки од корпата?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="one">Се вади <xliff:g id="COUNT">^1</xliff:g> ставка од корпата…</item>
+ <item quantity="other">Се вадат <xliff:g id="COUNT">^1</xliff:g> ставки од корпата…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="one">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да избрише <xliff:g id="COUNT">^2</xliff:g> аудиодатотека?</item>
<item quantity="other">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да избрише <xliff:g id="COUNT">^2</xliff:g> аудиодатотеки?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="one">Се брише <xliff:g id="COUNT">^1</xliff:g> аудиодатотека…</item>
+ <item quantity="other">Се бришат <xliff:g id="COUNT">^1</xliff:g> аудиодатотеки…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="one">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да избрише <xliff:g id="COUNT">^2</xliff:g> видео?</item>
<item quantity="other">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да избрише <xliff:g id="COUNT">^2</xliff:g> видеа?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="one">Се брише <xliff:g id="COUNT">^1</xliff:g> видео…</item>
+ <item quantity="other">Се бришат <xliff:g id="COUNT">^1</xliff:g> видеа…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="one">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да избрише <xliff:g id="COUNT">^2</xliff:g> фотографија?</item>
<item quantity="other">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да избрише <xliff:g id="COUNT">^2</xliff:g> фотографии?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="one">Се брише <xliff:g id="COUNT">^1</xliff:g> фотографија…</item>
+ <item quantity="other">Се бришат <xliff:g id="COUNT">^1</xliff:g> фотографии…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="one">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да избрише <xliff:g id="COUNT">^2</xliff:g> ставка?</item>
<item quantity="other">Да се дозволи <xliff:g id="APP_NAME_1">^1</xliff:g> да избрише <xliff:g id="COUNT">^2</xliff:g> ставки?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="one">Се брише <xliff:g id="COUNT">^1</xliff:g> ставка…</item>
+ <item quantity="other">Се бришат <xliff:g id="COUNT">^1</xliff:g> ставки…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> не може да обработува датотеки со аудиовизуелни содржини"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Транскодирањето е откажано"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Грешка при транскодирање"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Транскодирањето е успешно"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Транскодирањето започна"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Се транскодира…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Откажи"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Почекајте"</string>
</resources>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index d505748..a11ddef 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ഓഡിയോ ഫയലുകൾ പരിഷ്കരിക്കാൻ <xliff:g id="APP_NAME_1">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
<item quantity="one">ഈ ഓഡിയോ ഫയൽ പരിഷ്കരിക്കാൻ <xliff:g id="APP_NAME_0">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ഓഡിയോ ഫയലുകൾ പരിഷ്ക്കരിക്കുന്നു…</item>
+ <item quantity="one">ഓഡിയോ ഫയൽ പരിഷ്ക്കരിക്കുന്നു…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> വീഡിയോകൾ പരിഷ്കരിക്കാൻ <xliff:g id="APP_NAME_1">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
<item quantity="one">ഈ വീഡിയോ പരിഷ്കരിക്കാൻ <xliff:g id="APP_NAME_0">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> വീഡിയോകൾ പരിഷ്ക്കരിക്കുന്നു…</item>
+ <item quantity="one">വീഡിയോ പരിഷ്ക്കരിക്കുന്നു…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ഫോട്ടോകൾ പരിഷ്കരിക്കാൻ <xliff:g id="APP_NAME_1">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
<item quantity="one">ഈ ഫോട്ടോ പരിഷ്കരിക്കാൻ <xliff:g id="APP_NAME_0">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ഫോട്ടോകൾ പരിഷ്ക്കരിക്കുന്നു…</item>
+ <item quantity="one">ഫോട്ടോ പരിഷ്ക്കരിക്കുന്നു…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ഇനങ്ങൾ പരിഷ്കരിക്കാൻ <xliff:g id="APP_NAME_1">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
<item quantity="one">ഈ ഇനം പരിഷ്കരിക്കാൻ <xliff:g id="APP_NAME_0">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ഇനങ്ങൾ പരിഷ്ക്കരിക്കുന്നു…</item>
+ <item quantity="one">ഇനം പരിഷ്ക്കരിക്കുന്നു…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ഓഡിയോ ഫയലുകൾ ട്രാഷിലേക്ക് നീക്കാൻ <xliff:g id="APP_NAME_1">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
<item quantity="one">ഈ ഓഡിയോ ഫയൽ ട്രാഷിലേക്ക് നീക്കാൻ <xliff:g id="APP_NAME_0">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ഓഡിയോ ഫയലുകൾ ട്രാഷിലേക്ക് നീക്കുന്നു…</item>
+ <item quantity="one">ഓഡിയോ ഫയൽ ട്രാഷിലേക്ക് നീക്കുന്നു…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> വീഡിയോകൾ ട്രാഷിലേക്ക് നീക്കാൻ <xliff:g id="APP_NAME_1">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
<item quantity="one">ഈ വീഡിയോ ട്രാഷിലേക്ക് നീക്കാൻ <xliff:g id="APP_NAME_0">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> വീഡിയോകൾ ട്രാഷിലേക്ക് നീക്കുന്നു…</item>
+ <item quantity="one">വീഡിയോ ട്രാഷിലേക്ക് നീക്കുന്നു…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ഫോട്ടോകൾ ട്രാഷിലേക്ക് നീക്കാൻ <xliff:g id="APP_NAME_1">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
<item quantity="one">ഈ ഫോട്ടോ ട്രാഷിലേക്ക് നീക്കാൻ <xliff:g id="APP_NAME_0">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ഫോട്ടോകൾ ട്രാഷിലേക്ക് നീക്കുന്നു…</item>
+ <item quantity="one">ഫോട്ടോ ട്രാഷിലേക്ക് നീക്കുന്നു…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ഇനങ്ങൾ ട്രാഷിലേക്ക് നീക്കാൻ <xliff:g id="APP_NAME_1">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
<item quantity="one">ഈ ഇനം ട്രാഷിലേക്ക് നീക്കാൻ <xliff:g id="APP_NAME_0">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ഇനങ്ങൾ ട്രാഷിലേക്ക് നീക്കുന്നു…</item>
+ <item quantity="one">ഇനം ട്രാഷിലേക്ക് നീക്കുന്നു…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ഓഡിയോ ഫയലുകൾ ട്രാഷിന് പുറത്തേക്ക് നീക്കാൻ <xliff:g id="APP_NAME_1">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
<item quantity="one">ഈ ഓഡിയോ ഫയൽ ട്രാഷിന് പുറത്തേക്ക് നീക്കാൻ <xliff:g id="APP_NAME_0">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ഓഡിയോ ഫയലുകൾ ട്രാഷിലേക്ക് നീക്കുന്നു…</item>
+ <item quantity="one">ഓഡിയോ ഫയൽ ട്രാഷിലേക്ക് നീക്കുന്നു…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> വീഡിയോകൾ ട്രാഷിന് പുറത്തേക്ക് നീക്കാൻ <xliff:g id="APP_NAME_1">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
<item quantity="one">ഈ വീഡിയോ ട്രാഷിന് പുറത്തേക്ക് നീക്കാൻ <xliff:g id="APP_NAME_0">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> വീഡിയോകൾ ട്രാഷിൽ നിന്ന് നീക്കുന്നു…</item>
+ <item quantity="one">വീഡിയോ ട്രാഷിൽ നിന്ന് നീക്കുന്നു…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ഫോട്ടോകൾ ട്രാഷിന് പുറത്തേക്ക് നീക്കാൻ <xliff:g id="APP_NAME_1">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
<item quantity="one">ഈ ഫോട്ടോ ട്രാഷിന് പുറത്തേക്ക് നീക്കാൻ <xliff:g id="APP_NAME_0">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ഫോട്ടോകൾ ട്രാഷിൽ നിന്ന് നീക്കുന്നു…</item>
+ <item quantity="one">ഫോട്ടോ ട്രാഷിൽ നിന്ന് നീക്കുന്നു…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ഇനങ്ങൾ ട്രാഷിന് പുറത്തേക്ക് നീക്കാൻ <xliff:g id="APP_NAME_1">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
<item quantity="one">ഈ ഇനം ട്രാഷിന് പുറത്തേക്ക് നീക്കാൻ <xliff:g id="APP_NAME_0">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ഇനങ്ങൾ ട്രാഷിൽ നിന്ന് നീക്കുന്നു…</item>
+ <item quantity="one">ഇനം ട്രാഷിൽ നിന്ന് നീക്കുന്നു…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ഓഡിയോ ഫയലുകൾ ഇല്ലാതാക്കാൻ <xliff:g id="APP_NAME_1">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
<item quantity="one">ഈ ഓഡിയോ ഫയൽ ഇല്ലാതാക്കാൻ <xliff:g id="APP_NAME_0">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ഓഡിയോ ഫയലുകൾ ഇല്ലാതാക്കുന്നു…</item>
+ <item quantity="one">ഓഡിയോ ഫയൽ ഇല്ലാതാക്കുന്നു…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> വീഡിയോകൾ ഇല്ലാതാക്കാൻ <xliff:g id="APP_NAME_1">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
<item quantity="one">ഈ വീഡിയോ ഇല്ലാതാക്കാൻ <xliff:g id="APP_NAME_0">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> വീഡിയോകൾ ഇല്ലാതാക്കുന്നു…</item>
+ <item quantity="one">വീഡിയോ ഇല്ലാതാക്കുന്നു…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ഫോട്ടോകൾ ഇല്ലാതാക്കാൻ <xliff:g id="APP_NAME_1">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
<item quantity="one">ഈ ഫോട്ടോ ഇല്ലാതാക്കാൻ <xliff:g id="APP_NAME_0">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ഫോട്ടോകൾ ഇല്ലാതാക്കുന്നു…</item>
+ <item quantity="one">ഫോട്ടോ ഇല്ലാതാക്കുന്നു…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ഇനങ്ങൾ ഇല്ലാതാക്കാൻ <xliff:g id="APP_NAME_1">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
<item quantity="one">ഈ ഇനം ഇല്ലാതാക്കാൻ <xliff:g id="APP_NAME_0">^1</xliff:g> എന്നതിനെ അനുവദിക്കണോ?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ഇനങ്ങൾ ഇല്ലാതാക്കുന്നു…</item>
+ <item quantity="one">ഇനം ഇല്ലാതാക്കുന്നു…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> എന്നതിന് മീഡിയ ഫയലുകൾ പ്രോസസ് ചെയ്യാനാകില്ല"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"മീഡിയ പ്രോസസ് ചെയ്യൽ റദ്ദാക്കി"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"മീഡിയ പ്രോസസ് ചെയ്യുന്നതിൽ പിശക്"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"മീഡിയ പ്രോസസ് ചെയ്യൽ പൂർത്തിയായി"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"മീഡിയ പ്രോസസ് ചെയ്യൽ ആരംഭിച്ചു"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"മീഡിയ പ്രോസസ് ചെയ്യുന്നു…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"റദ്ദാക്കുക"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"കാത്തിരിക്കുക"</string>
</resources>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 8c7a39b..3b791d8 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-д <xliff:g id="COUNT">^2</xliff:g> аудио файл өөрчлөхийг зөвшөөрөх үү?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>-д энэ аудио файлыг өөрчлөхийг зөвшөөрөх үү?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> аудио файлыг өөрчилж байна…</item>
+ <item quantity="one">Аудио файлыг өөрчилж байна…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-д <xliff:g id="COUNT">^2</xliff:g> видео өөрчлөхийг зөвшөөрөх үү?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>-д энэ видеог өөрчлөхийг зөвшөөрөх үү?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> видеог өөрчилж байна…</item>
+ <item quantity="one">Видеог өөрчилж байна…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-д <xliff:g id="COUNT">^2</xliff:g> зураг өөрчлөхийг зөвшөөрөх үү?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>-д энэ зургийг өөрчлөхийг зөвшөөрөх үү?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> зургийг өөрчилж байна…</item>
+ <item quantity="one">Зургийг өөрчилж байна…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-д <xliff:g id="COUNT">^2</xliff:g> зүйл өөрчлөхийг зөвшөөрөх үү?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>-д энэ зүйлийг өөрчлөхийг зөвшөөрөх үү?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> зүйлийг өөрчилж байна…</item>
+ <item quantity="one">Зүйлийг өөрчилж байна…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-д <xliff:g id="COUNT">^2</xliff:g> аудио файлыг хогийн сав руу зөөхийг зөвшөөрөх үү?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>-д энэ аудио файлыг хогийн сав руу зөөхийг зөвшөөрөх үү?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> аудио файлыг хогийн сав руу зөөж байна…</item>
+ <item quantity="one">Аудио файлыг хогийн сав руу зөөж байна…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-д <xliff:g id="COUNT">^2</xliff:g> видеог хогийн сав руу зөөхийг зөвшөөрөх үү?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>-д энэ видеог хогийн сав руу зөөхийг зөвшөөрөх үү?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> видеог хогийн сав руу зөөж байна…</item>
+ <item quantity="one">Видеог хогийн сав руу зөөж байна…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-д <xliff:g id="COUNT">^2</xliff:g> зургийг хогийн сав руу зөөхийг зөвшөөрөх үү?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>-д энэ зургийг хогийн сав руу зөөхийг зөвшөөрөх үү?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> зургийг хогийн сав руу зөөж байна…</item>
+ <item quantity="one">Зургийг хогийн сав руу зөөж байна…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-д хогийн сав руу <xliff:g id="COUNT">^2</xliff:g> зүйлийг зөөхийг зөвшөөрөх үү?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>-д энэ зүйлийг хогийн сав руу зөөхийг зөвшөөрөх үү?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> зүйлийг хогийн сав руу зөөж байна…</item>
+ <item quantity="one">Зүйлийг хогийн сав руу зөөж байна…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-д <xliff:g id="COUNT">^2</xliff:g> аудио файлыг хогийн савнаас гаргахыг зөвшөөрөх үү?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>-д энэ аудио файлыг хогийн савнаас гаргахыг зөвшөөрөх үү?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> аудио файлыг хогийн савнаас гадагш зөөж байна…</item>
+ <item quantity="one">Аудио файлыг хогийн савнаас гадагш зөөж байна…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-д <xliff:g id="COUNT">^2</xliff:g> видеог хогийн савнаас гаргахыг зөвшөөрөх үү?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>-д энэ видеог хогийн савнаас гаргахыг зөвшөөрөх үү?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> видеог хогийн савнаас гадагш зөөж байна…</item>
+ <item quantity="one">Видеог хогийн савнаас гадагш зөөж байна…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-д <xliff:g id="COUNT">^2</xliff:g> зургийг хогийн савнаас гаргахыг зөвшөөрөх үү?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>-д энэ зургийг хогийн савнаас гаргахыг зөвшөөрөх үү?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> зургийг хогийн савнаас гадагш зөөж байна…</item>
+ <item quantity="one">Зургийг хогийн савнаас гадагш зөөж байна…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-д <xliff:g id="COUNT">^2</xliff:g> зүйлийг хогийн савнаас гаргахыг зөвшөөрөх үү?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>-д энэ зүйлийг хогийн савнаас гаргахыг зөвшөөрөх үү?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> зүйлийг хогийн савнаас гадагш зөөж байна…</item>
+ <item quantity="one">Зүйлийг хогийн савнаас гадагш зөөж байна…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-д <xliff:g id="COUNT">^2</xliff:g> аудио файл устгахыг зөвшөөрөх үү?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>-д энэ аудио файлыг устгахыг зөвшөөрөх үү?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> аудио файлыг устгаж байна…</item>
+ <item quantity="one">Аудио файлыг устгаж байна…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-д <xliff:g id="COUNT">^2</xliff:g> видео устгахыг зөвшөөрөх үү?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>-д энэ видеог устгахыг зөвшөөрөх үү?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> видеог устгаж байна…</item>
+ <item quantity="one">Видеог устгаж байна…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-д <xliff:g id="COUNT">^2</xliff:g> зураг устгахыг зөвшөөрөх үү?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>-д энэ зургийг устгахыг зөвшөөрөх үү?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> зургийг устгаж байна…</item>
+ <item quantity="one">Зургийг устгаж байна…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>-д <xliff:g id="COUNT">^2</xliff:g> зүйл устгахыг зөвшөөрөх үү?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g>-д энэ зүйлийг устгахыг зөвшөөрөх үү?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> зүйлийг устгаж байна…</item>
+ <item quantity="one">Зүйлийг устгаж байна…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> медиа файлуудыг боловсруулах боломжгүй"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Медиагийн боловсруулалтыг цуцалсан"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Медиаг боловсруулахад алдаа гарлаа"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Медиаг амжилттай боловсруулсан"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Медиаг боловсруулж эхэлсэн"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Медиаг боловсруулж байна…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Цуцлах"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Хүлээх"</string>
</resources>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index b110be3..98bef88 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ला <xliff:g id="COUNT">^2</xliff:g> ऑडिओ फाइल सुधारित करण्याची परवानगी द्यायची आहे का?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ला ही ऑडिओ फाइल सुधारित करण्याची परवानगी द्यायची आहे का?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ऑडिओ फाइल बदलत आहे…</item>
+ <item quantity="one">ऑडिओ फाइल बदलत आहे…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ला <xliff:g id="COUNT">^2</xliff:g> व्हिडिओ सुधारित करण्याची परवानगी द्यायची आहे का?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ला हा व्हिडिओ सुधारित करण्याची परवानगी द्यायची आहे का?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> व्हिडिओ बदलत आहे…</item>
+ <item quantity="one">व्हिडिओ बदलत आहे…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ला <xliff:g id="COUNT">^2</xliff:g> फोटो सुधारित करण्याची परवानगी द्यायची आहे का?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ला हा फोटो सुधारित करण्याची परवानगी द्यायची आहे का?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> फोटो बदलत आहे…</item>
+ <item quantity="one">फोटो बदलत आहे…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ला <xliff:g id="COUNT">^2</xliff:g> आयटम सुधारित करण्याची परवानगी द्यायची आहे का?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ला हा आयटम सुधारित करण्याची परवानगी द्यायची आहे का?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> आयटम बदलत आहे…</item>
+ <item quantity="one">आयटम बदलत आहे…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ला <xliff:g id="COUNT">^2</xliff:g> ऑडिओ फाइल कचऱ्यामध्ये हलवायची परवानगी द्यायची आहे का?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ला ही ऑडिओ फाइल कचऱ्यामध्ये हलवायची परवानगी द्यायची आहे का?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ऑडिओ ट्रॅशमध्ये हलवत आहे…</item>
+ <item quantity="one">ऑडिओ ट्रॅशमध्ये हलवत आहे…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ला <xliff:g id="COUNT">^2</xliff:g> व्हिडिओ कचऱ्यामध्ये हलवायची परवानगी द्यायची आहे का?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ला हा व्हिडिओ कचऱ्यामध्ये हलवायची परवानगी द्यायची आहे का?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> व्हिडिओ ट्रॅशमध्ये हलवत आहे…</item>
+ <item quantity="one">व्हिडिओ ट्रॅशमध्ये हलवत आहे…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ला <xliff:g id="COUNT">^2</xliff:g> फोटो कचऱ्यामध्ये हलवायची परवानगी द्यायची आहे का?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ला हा फोटो कचऱ्यामध्ये हलवायची परवानगी द्यायची आहे का?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> फोटो ट्रॅशमध्ये हलवत आहे…</item>
+ <item quantity="one">फोटो ट्रॅशमध्ये हलवत आहे…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ला <xliff:g id="COUNT">^2</xliff:g> आयटम कचऱ्यामध्ये हलवण्याची परवानगी द्यायची आहे का?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ला हा आयटम कचऱ्यामध्ये हलवायची परवानगी द्यायची आहे का?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> आयटम ट्रॅशमध्ये हलवत आहे…</item>
+ <item quantity="one">आयटम ट्रॅशमध्ये हलवत आहे…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ला <xliff:g id="COUNT">^2</xliff:g> ऑडिओ फाइल कचऱ्यामधून बाहेर हलवायची परवानगी द्यायची आहे का?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ला ही ऑडिओ फाइल कचऱ्यामधून बाहेर हलवायची परवानगी द्यायची आहे का?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ऑडिओ फाइल ट्रॅशमधून बाहेर हलवत आहे…</item>
+ <item quantity="one">ऑडिओ फाइल ट्रॅशमधून बाहेर हलवत आहे…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ला <xliff:g id="COUNT">^2</xliff:g> व्हिडिओ कचऱ्यामधून बाहेर हलवायची परवानगी द्यायची आहे का?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ला हा व्हिडिओ कचऱ्यामधून बाहेर हलवायची परवानगी द्यायची आहे का?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> व्हिडिओ ट्रॅशमधून बाहेर हलवत आहे…</item>
+ <item quantity="one">व्हिडिओ ट्रॅशमधून बाहेर हलवत आहे…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ला <xliff:g id="COUNT">^2</xliff:g> फोटो कचऱ्यामधून बाहेर हलवायची परवानगी द्यायची आहे का?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ला हा फोटो कचऱ्यामधून बाहेर हलवायची परवानगी द्यायची आहे का?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> फोटो ट्रॅशमधून बाहेर हलवत आहे…</item>
+ <item quantity="one">फोटो ट्रॅशमधून बाहेर हलवत आहे…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ला <xliff:g id="COUNT">^2</xliff:g> आयटम कचऱ्यामधून बाहेर हलवायची परवानगी द्यायची आहे का?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ला हा आयटम कचऱ्यामधून बाहेर हलवायची परवानगी द्यायची आहे का?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> आयटम ट्रॅशमधून बाहेर हलवत आहे…</item>
+ <item quantity="one">आयटम ट्रॅशमधून बाहेर हलवत आहे…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ला <xliff:g id="COUNT">^2</xliff:g> ऑडिओ फाइल हटवायची परवानगी द्यायची आहे का?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ला ही ऑडिओ फाइल हटवायची परवानगी द्यायची आहे का?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ऑडिओ फाइल हटवत आहे…</item>
+ <item quantity="one">ऑडिओ फाइल हटवत आहे…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ला <xliff:g id="COUNT">^2</xliff:g> व्हिडिओ हटवायची परवानगी द्यायची आहे का?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ला हा व्हिडिओ हटवायची परवानगी द्यायची आहे का?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> व्हिडिओ हटवत आहे…</item>
+ <item quantity="one">व्हिडिओ हटवत आहे…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ला <xliff:g id="COUNT">^2</xliff:g> फोटो हटवायची परवानगी द्यायची आहे का?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ला हा फोटो हटवायची परवानगी द्यायची आहे का?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> फोटो हटवत आहे…</item>
+ <item quantity="one">फोटो हटवत आहे…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ला <xliff:g id="COUNT">^2</xliff:g> आयटम हटवायची परवानगी द्यायची आहे का?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ला हा आयटम हटवायची परवानगी द्यायची आहे का?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> आयटम हटवत आहे…</item>
+ <item quantity="one">आयटम हटवत आहे…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> मीडिया फाइलवर प्रक्रिया करू नाही"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"मीडियावर प्रक्रिया करणे रद्द केले"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"मीडियावर प्रक्रिया करण्यासंबंधित एरर"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"मीडियावर प्रक्रिया करणे यशस्वी झाले"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"मीडियावर प्रक्रिया सुरू झाली"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"मीडियावर प्रक्रिया सुरू आहे…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"रद्द करा"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"प्रतीक्षा करा"</string>
</resources>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 067cc43..dc5d040 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">Benarkan <xliff:g id="APP_NAME_1">^1</xliff:g> mengubah suai <xliff:g id="COUNT">^2</xliff:g> fail audio?</item>
<item quantity="one">Benarkan <xliff:g id="APP_NAME_0">^1</xliff:g> mengubah suai fail audio ini?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other">Mengubah suai <xliff:g id="COUNT">^1</xliff:g> fail audio…</item>
+ <item quantity="one">Mengubah suai fail audio…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">Benarkan <xliff:g id="APP_NAME_1">^1</xliff:g> mengubah suai <xliff:g id="COUNT">^2</xliff:g> video?</item>
<item quantity="one">Benarkan <xliff:g id="APP_NAME_0">^1</xliff:g> mengubah suai video ini?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other">Mengubah suai <xliff:g id="COUNT">^1</xliff:g> video…</item>
+ <item quantity="one">Mengubah suai video…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">Benarkan <xliff:g id="APP_NAME_1">^1</xliff:g> mengubah suai <xliff:g id="COUNT">^2</xliff:g> foto?</item>
<item quantity="one">Benarkan <xliff:g id="APP_NAME_0">^1</xliff:g> mengubah suai foto ini?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other">Mengubah suai <xliff:g id="COUNT">^1</xliff:g> foto…</item>
+ <item quantity="one">Mengubah suai foto…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">Benarkan <xliff:g id="APP_NAME_1">^1</xliff:g> mengubah suai <xliff:g id="COUNT">^2</xliff:g> item?</item>
<item quantity="one">Benarkan <xliff:g id="APP_NAME_0">^1</xliff:g> mengubah suai item ini?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other">Mengubah suai <xliff:g id="COUNT">^1</xliff:g> item…</item>
+ <item quantity="one">Mengubah suai item…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">Benarkan <xliff:g id="APP_NAME_1">^1</xliff:g> mengalihkan <xliff:g id="COUNT">^2</xliff:g> fail audio ke sampah?</item>
<item quantity="one">Benarkan <xliff:g id="APP_NAME_0">^1</xliff:g> mengalihkan fail audio ini ke sampah?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other">Mengalihkan <xliff:g id="COUNT">^1</xliff:g> fail audio ke sampah…</item>
+ <item quantity="one">Mengalihkan fail audio ke sampah…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">Benarkan <xliff:g id="APP_NAME_1">^1</xliff:g> mengalihkan <xliff:g id="COUNT">^2</xliff:g> video ke sampah?</item>
<item quantity="one">Benarkan <xliff:g id="APP_NAME_0">^1</xliff:g> mengalihkan video ini ke sampah?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other">Mengalihkan <xliff:g id="COUNT">^1</xliff:g> video ke sampah…</item>
+ <item quantity="one">Mengalihkan video ke sampah…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">Benarkan <xliff:g id="APP_NAME_1">^1</xliff:g> mengalihkan <xliff:g id="COUNT">^2</xliff:g> foto ke sampah?</item>
<item quantity="one">Benarkan <xliff:g id="APP_NAME_0">^1</xliff:g> mengalihkan foto ini ke sampah?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other">Mengalihkan <xliff:g id="COUNT">^1</xliff:g> foto ke sampah…</item>
+ <item quantity="one">Mengalihkan foto ke sampah…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">Benarkan <xliff:g id="APP_NAME_1">^1</xliff:g> mengalihkan <xliff:g id="COUNT">^2</xliff:g> item ke sampah?</item>
<item quantity="one">Benarkan <xliff:g id="APP_NAME_0">^1</xliff:g> mengalihkan item ini ke sampah?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other">Mengalihkan <xliff:g id="COUNT">^1</xliff:g> item ke sampah…</item>
+ <item quantity="one">Mengalihkan item ke sampah…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">Benarkan <xliff:g id="APP_NAME_1">^1</xliff:g> mengalihkan <xliff:g id="COUNT">^2</xliff:g> fail audio keluar daripada sampah?</item>
<item quantity="one">Benarkan <xliff:g id="APP_NAME_0">^1</xliff:g> mengalihkan fail audio ini keluar daripada sampah?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other">Mengalihkan <xliff:g id="COUNT">^1</xliff:g> fail audio keluar dari sampah…</item>
+ <item quantity="one">Mengalihkan fail audio keluar dari sampah…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">Benarkan <xliff:g id="APP_NAME_1">^1</xliff:g> mengalihkan <xliff:g id="COUNT">^2</xliff:g> video keluar daripada sampah?</item>
<item quantity="one">Benarkan <xliff:g id="APP_NAME_0">^1</xliff:g> mengalihkan video ini keluar daripada sampah?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other">Mengalih <xliff:g id="COUNT">^1</xliff:g> video keluar dari sampah…</item>
+ <item quantity="one">Mengalih video keluar dari sampah…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">Benarkan <xliff:g id="APP_NAME_1">^1</xliff:g> mengalihkan <xliff:g id="COUNT">^2</xliff:g> foto keluar daripada sampah?</item>
<item quantity="one">Benarkan <xliff:g id="APP_NAME_0">^1</xliff:g> mengalihkan foto ini keluar daripada sampah?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other">Mengalih <xliff:g id="COUNT">^1</xliff:g> foto keluar dari sampah…</item>
+ <item quantity="one">Mengalih foto keluar dari sampah…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">Benarkan <xliff:g id="APP_NAME_1">^1</xliff:g> mengalihkan <xliff:g id="COUNT">^2</xliff:g> item keluar daripada sampah?</item>
<item quantity="one">Benarkan <xliff:g id="APP_NAME_0">^1</xliff:g> mengalihkan item ini keluar daripada sampah?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other">Mengalih <xliff:g id="COUNT">^1</xliff:g> item keluar dari sampah…</item>
+ <item quantity="one">Mengalih item keluar dari sampah…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">Benarkan <xliff:g id="APP_NAME_1">^1</xliff:g> memadamkan <xliff:g id="COUNT">^2</xliff:g> fail audio?</item>
<item quantity="one">Benarkan <xliff:g id="APP_NAME_0">^1</xliff:g> memadamkan fail audio ini?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other">Memadamkan <xliff:g id="COUNT">^1</xliff:g> fail audio…</item>
+ <item quantity="one">Memadamkan fail audio…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">Benarkan <xliff:g id="APP_NAME_1">^1</xliff:g> memadamkan <xliff:g id="COUNT">^2</xliff:g> video?</item>
<item quantity="one">Benarkan <xliff:g id="APP_NAME_0">^1</xliff:g> memadamkan video ini?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other">Memadamkan <xliff:g id="COUNT">^1</xliff:g> video…</item>
+ <item quantity="one">Memadamkan video…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">Benarkan <xliff:g id="APP_NAME_1">^1</xliff:g> memadamkan <xliff:g id="COUNT">^2</xliff:g> foto?</item>
<item quantity="one">Benarkan <xliff:g id="APP_NAME_0">^1</xliff:g> memadamkan foto ini?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other">Memadamkan <xliff:g id="COUNT">^1</xliff:g> foto…</item>
+ <item quantity="one">Memadamkan foto…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">Benarkan <xliff:g id="APP_NAME_1">^1</xliff:g> memadamkan <xliff:g id="COUNT">^2</xliff:g> item?</item>
<item quantity="one">Benarkan <xliff:g id="APP_NAME_0">^1</xliff:g> memadamkan item ini?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other">Memadamkan <xliff:g id="COUNT">^1</xliff:g> item…</item>
+ <item quantity="one">Memadamkan item…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> tidak dapat memproses fail media"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Pemprosesan media dibatalkan"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Ralat pemprosesan media"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Pemprosesan media berjaya"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Pemprosesan media telah bermula"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Memproses media…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Batal"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Tunggu"</string>
</resources>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index ab3766c..ce0b311 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ကို အသံဖိုင် <xliff:g id="COUNT">^2</xliff:g> ဖိုင် ပြင်ဆင်ခွင့်ပြုမလား။</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ကို ဤအသံဖိုင် ပြင်ဆင်ခွင့်ပြုမလား။</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other">အသံဖိုင် <xliff:g id="COUNT">^1</xliff:g> ခုကို ပြင်ဆင်နေသည်…</item>
+ <item quantity="one">အသံဖိုင်ကို ပြင်ဆင်နေသည်…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ကို ဗီဒီယို <xliff:g id="COUNT">^2</xliff:g> ခု ပြင်ဆင်ခွင့်ပြုမလား။</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ကို ဤဗီဒီယို ပြင်ဆင်ခွင့်ပြုမလား။</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other">ဗီဒီယို <xliff:g id="COUNT">^1</xliff:g> ခုကို ပြင်ဆင်နေသည်…</item>
+ <item quantity="one">ဗီဒီယိုကို ပြင်ဆင်နေသည်…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> အား ဓာတ်ပုံ <xliff:g id="COUNT">^2</xliff:g> ပုံကို ပြုပြင်ခွင့်ပြုမလား။</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ကို ဤဓာတ်ပုံ ပြင်ဆင်ခွင့်ပြုမလား။</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other">ဓာတ်ပုံ <xliff:g id="COUNT">^1</xliff:g> ပုံကို ပြင်ဆင်နေသည်…</item>
+ <item quantity="one">ဓာတ်ပုံကို ပြင်ဆင်နေသည်…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ကို ဤအရာ <xliff:g id="COUNT">^2</xliff:g> ခု ပြင်ဆင်ခွင့်ပြုမလား။</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ကို ဤအရာ ပြင်ဆင်ခွင့်ပြုမလား။</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other">ဖိုင် <xliff:g id="COUNT">^1</xliff:g> ခုကို ပြင်ဆင်နေသည်…</item>
+ <item quantity="one">ဖိုင်ကို ပြင်ဆင်နေသည်…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> အား အသံဖိုင် <xliff:g id="COUNT">^2</xliff:g> ဖိုင်ကို အမှိုက်ပုံးသို့ ရွှေ့ခွင့်ပြုမလား။</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> အား ဤအသံဖိုင်ကို အမှိုက်ပုံးသို့ ရွှေ့ခွင့်ပြုမလား။</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other">အသံဖိုင် <xliff:g id="COUNT">^1</xliff:g> ခုကို အမှိုက်ပုံးထဲသို့ ရွှေ့နေသည်…</item>
+ <item quantity="one">အသံဖိုင်ကို အမှိုက်ပုံးထဲသို့ ရွှေ့နေသည်…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> အား ဗီဒီယို <xliff:g id="COUNT">^2</xliff:g> ခုကို အမှိုက်ပုံးသို့ ရွှေ့ခွင့်ပြုမလား။</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> အား ဤဗီဒီယိုကို အမှိုက်ပုံးသို့ ရွှေ့ခွင့်ပြုမလား။</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other">ဗီဒီယို <xliff:g id="COUNT">^1</xliff:g> ခုကို အမှိုက်ပုံးထဲသို့ ရွှေ့နေသည်…</item>
+ <item quantity="one">ဗီဒီယိုကို အမှိုက်ပုံးထဲသို့ ရွှေ့နေသည်…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> အား ဓာတ်ပုံ <xliff:g id="COUNT">^2</xliff:g> ပုံကို အမှိုက်ပုံးသို့ ရွှေ့ခွင့်ပြုမလား။</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> အား ဤဓာတ်ပုံကို အမှိုက်ပုံးသို့ ရွှေ့ခွင့်ပြုမလား။</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other">ဓာတ်ပုံ <xliff:g id="COUNT">^1</xliff:g> ပုံကို အမှိုက်ပုံးထဲသို့ ရွှေ့နေသည်…</item>
+ <item quantity="one">ဓာတ်ပုံကို အမှိုက်ပုံးထဲသို့ ရွှေ့နေသည်…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> အား ဤအရာ <xliff:g id="COUNT">^2</xliff:g> ခုကို အမှိုက်ပုံးသို့ ရွှေ့ခွင့်ပြုမလား။</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> အား ဤအရာကို အမှိုက်ပုံးသို့ ရွှေ့ခွင့်ပြုမလား။</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other">ဖိုင် <xliff:g id="COUNT">^1</xliff:g> ခုကို အမှိုက်ပုံးထဲသို့ ရွှေ့နေသည်…</item>
+ <item quantity="one">ဖိုင်ကို အမှိုက်ပုံးထဲသို့ ရွှေ့နေသည်…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> အား အသံဖိုင် <xliff:g id="COUNT">^2</xliff:g> ဖိုင်ကို အမှိုက်ပုံးထဲမှ ရွှေ့ခွင့်ပြုမလား။</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> အား ဤအသံဖိုင်ကို အမှိုက်ပုံးထဲမှ ရွှေ့ခွင့်ပြုမလား။</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other">အသံဖိုင်ကို <xliff:g id="COUNT">^1</xliff:g> ခုကို အမှိုက်ပုံးထဲမှ ရွှေ့နေသည်…</item>
+ <item quantity="one">အသံဖိုင်ကို အမှိုက်ပုံးထဲမှ ရွှေ့နေသည်…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> အား ဗီဒီယို <xliff:g id="COUNT">^2</xliff:g> ခုကို အမှိုက်ပုံးထဲမှ ရွှေ့ခွင့်ပြုမလား။</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> အား ဤဗီဒီယိုကို အမှိုက်ပုံးထဲမှ ရွှေ့ခွင့်ပြုမလား။</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other">ဗီဒီယို <xliff:g id="COUNT">^1</xliff:g> ခုကို အမှိုက်ပုံးထဲမှ ရွှေ့နေသည်…</item>
+ <item quantity="one">ဗီဒီယိုကို အမှိုက်ပုံးထဲမှ ရွှေ့နေသည်…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> အား ဓာတ်ပုံ <xliff:g id="COUNT">^2</xliff:g> ပုံကို အမှိုက်ပုံးထဲမှ ရွှေ့ခွင့်ပြုမလား။</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> အား ဤဓာတ်ပုံကို အမှိုက်ပုံးထဲမှ ရွှေ့ခွင့်ပြုမလား။</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other">ဓာတ်ပုံ <xliff:g id="COUNT">^1</xliff:g> ပုံကို အမှိုက်ပုံးထဲမှ ရွှေ့နေသည်…</item>
+ <item quantity="one">ဓာတ်ပုံကို အမှိုက်ပုံးထဲမှ ရွှေ့နေသည်…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> အား ဤအရာ <xliff:g id="COUNT">^2</xliff:g> ခုကို အမှိုက်ပုံးထဲမှ ရွှေ့ခွင့်ပြုမလား။</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> အား ဤအရာကို အမှိုက်ပုံးထဲမှ ရွှေ့ခွင့်ပြုမလား။</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other">ဖိုင် <xliff:g id="COUNT">^1</xliff:g> ခုကို အမှိုက်ပုံးထဲမှ ရွှေ့နေသည်…</item>
+ <item quantity="one">ဖိုင်ကို အမှိုက်ပုံးထဲမှ ရွှေ့နေသည်…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> အား အသံဖိုင် <xliff:g id="COUNT">^2</xliff:g> ဖိုင်ကို ဖျက်ခွင့်ပြုမလား။</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> အား ဤအသံဖိုင်ကို ဖျက်ခွင့်ပြုမလား။</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other">အသံဖိုင် <xliff:g id="COUNT">^1</xliff:g> ခုကို ဖျက်နေသည်…</item>
+ <item quantity="one">အသံဖိုင်ကို ဖျက်နေသည်…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ကို ဗီဒီယို <xliff:g id="COUNT">^2</xliff:g> ခု ဖျက်ခွင့်ပြုမလား။</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ကို ဤဗီဒီယို ဖျက်ခွင့်ပြုမလား။</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other">ဗီဒီယို <xliff:g id="COUNT">^1</xliff:g> ခုကို ဖျက်နေသည်…</item>
+ <item quantity="one">ဗီဒီယိုကို ဖျက်နေသည်…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ကို ဓာတ်ပုံ <xliff:g id="COUNT">^2</xliff:g> ပုံ ဖျက်ခွင့်ပြုမလား။</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ကို ဤဓာတ်ပုံ ဖျက်ခွင့်ပြုမလား။</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other">ဓာတ်ပုံ <xliff:g id="COUNT">^1</xliff:g> ပုံကို ဖျက်နေသည်…</item>
+ <item quantity="one">ဓာတ်ပုံကို ဖျက်နေသည်…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> အား ဤအရာ <xliff:g id="COUNT">^2</xliff:g> ခုကို ဖျက်ခွင့်ပြုမလား။</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> အား ဤအရာကို ဖျက်ခွင့်ပြုမလား။</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other">ဖိုင် <xliff:g id="COUNT">^1</xliff:g> ခုကို ဖျက်နေသည်…</item>
+ <item quantity="one">ဖိုင်ကို ဖျက်နေသည်…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> က မီဒီယာဖိုင်များကို မလုပ်ဆောင်နိုင်ပါ"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"မီဒီယာ လုပ်ဆောင်ခြင်းကို ရပ်လိုက်သည်"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"မီဒီယာ လုပ်ဆောင်ခြင်း အမှားရှိသည်"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"မီဒီယာ လုပ်ဆောင်ခြင်း အောင်မြင်ပါသည်"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"မီဒီယာ လုပ်ဆောင်ခြင်း စတင်လိုက်သည်"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"မီဒီယာကို လုပ်ဆောင်နေသည်…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"မလုပ်တော့"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"စောင့်ရန်"</string>
</resources>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 35fd892..3ebc4c1 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">Vil du tillate at <xliff:g id="APP_NAME_1">^1</xliff:g> endrer <xliff:g id="COUNT">^2</xliff:g> lydfiler?</item>
<item quantity="one">Vil du tillate at <xliff:g id="APP_NAME_0">^1</xliff:g> endrer denne lydfilen?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other">Endrer <xliff:g id="COUNT">^1</xliff:g> lydfiler …</item>
+ <item quantity="one">Endrer lydfilen …</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">Vil du tillate at <xliff:g id="APP_NAME_1">^1</xliff:g> endrer <xliff:g id="COUNT">^2</xliff:g> videoer?</item>
<item quantity="one">Vil du tillate at <xliff:g id="APP_NAME_0">^1</xliff:g> endrer denne videoen?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other">Endrer <xliff:g id="COUNT">^1</xliff:g> videoer …</item>
+ <item quantity="one">Endrer videoen …</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">Vil du tillate at <xliff:g id="APP_NAME_1">^1</xliff:g> endrer <xliff:g id="COUNT">^2</xliff:g> bilder?</item>
<item quantity="one">Vil du tillate at <xliff:g id="APP_NAME_0">^1</xliff:g> endrer dette bildet?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other">Endrer <xliff:g id="COUNT">^1</xliff:g> bilder …</item>
+ <item quantity="one">Endrer bildet …</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">Vil du tillate at <xliff:g id="APP_NAME_1">^1</xliff:g> endrer <xliff:g id="COUNT">^2</xliff:g> elementer?</item>
<item quantity="one">Vil du tillate at <xliff:g id="APP_NAME_0">^1</xliff:g> endrer dette elementet?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other">Endrer <xliff:g id="COUNT">^1</xliff:g> elementer …</item>
+ <item quantity="one">Endrer elementet …</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">Vil du tillate at <xliff:g id="APP_NAME_1">^1</xliff:g> flytter <xliff:g id="COUNT">^2</xliff:g> lydfiler til papirkurven?</item>
<item quantity="one">Vil du tillate at <xliff:g id="APP_NAME_0">^1</xliff:g> flytter denne lydfilen til papirkurven?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other">Flytter <xliff:g id="COUNT">^1</xliff:g> lydfiler til papirkurven …</item>
+ <item quantity="one">Flytter lydfilen til papirkurven …</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">Vil du tillate at <xliff:g id="APP_NAME_1">^1</xliff:g> flytter <xliff:g id="COUNT">^2</xliff:g> videoer til papirkurven?</item>
<item quantity="one">Vil du tillate at <xliff:g id="APP_NAME_0">^1</xliff:g> flytter denne videoen til papirkurven?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other">Flytter <xliff:g id="COUNT">^1</xliff:g> videoer til papirkurven …</item>
+ <item quantity="one">Flytter videoen til papirkurven …</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">Vil du tillate at <xliff:g id="APP_NAME_1">^1</xliff:g> flytter <xliff:g id="COUNT">^2</xliff:g> bilder til papirkurven?</item>
<item quantity="one">Vil du tillate at <xliff:g id="APP_NAME_0">^1</xliff:g> flytter dette bildet til papirkurven?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other">Flytter <xliff:g id="COUNT">^1</xliff:g> bilder til papirkurven …</item>
+ <item quantity="one">Flytter bildet til papirkurven …</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">Vil du tillate at <xliff:g id="APP_NAME_1">^1</xliff:g> flytter <xliff:g id="COUNT">^2</xliff:g> elementer til papirkurven?</item>
<item quantity="one">Vil du tillate at <xliff:g id="APP_NAME_0">^1</xliff:g> flytter dette elementet til papirkurven?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other">Flytter <xliff:g id="COUNT">^1</xliff:g> elementer til papirkurven …</item>
+ <item quantity="one">Flytter elementet til papirkurven …</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">Vil du tillate at <xliff:g id="APP_NAME_1">^1</xliff:g> flytter <xliff:g id="COUNT">^2</xliff:g> lydfiler ut av papirkurven?</item>
<item quantity="one">Vil du tillate at <xliff:g id="APP_NAME_0">^1</xliff:g> flytter denne lydfilen ut av papirkurven?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other">Flytter <xliff:g id="COUNT">^1</xliff:g> lydfiler ut av papirkurven …</item>
+ <item quantity="one">Flytter lydfilen ut av papirkurven …</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">Vil du tillate at <xliff:g id="APP_NAME_1">^1</xliff:g> flytter <xliff:g id="COUNT">^2</xliff:g> videoer ut av papirkurven?</item>
<item quantity="one">Vil du tillate at <xliff:g id="APP_NAME_0">^1</xliff:g> flytter denne videoen ut av papirkurven?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other">Flytter <xliff:g id="COUNT">^1</xliff:g> videoer ut av papirkurven …</item>
+ <item quantity="one">Flytter videoen ut av papirkurven …</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">Vil du tillate at <xliff:g id="APP_NAME_1">^1</xliff:g> flytter <xliff:g id="COUNT">^2</xliff:g> bilder ut av papirkurven?</item>
<item quantity="one">Vil du tillate at <xliff:g id="APP_NAME_0">^1</xliff:g> flytter dette bildet ut av papirkurven?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other">Flytter <xliff:g id="COUNT">^1</xliff:g> bilder ut av papirkurven …</item>
+ <item quantity="one">Flytter bildet ut av papirkurven …</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">Vil du tillate at <xliff:g id="APP_NAME_1">^1</xliff:g> flytter <xliff:g id="COUNT">^2</xliff:g> elementer ut av papirkurven?</item>
<item quantity="one">Vil du tillate at <xliff:g id="APP_NAME_0">^1</xliff:g> flytter dette elementet ut av papirkurven?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other">Flytter <xliff:g id="COUNT">^1</xliff:g> elementer ut av papirkurven …</item>
+ <item quantity="one">Flytter elementet ut av papirkurven …</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">Vil du tillate at <xliff:g id="APP_NAME_1">^1</xliff:g> sletter <xliff:g id="COUNT">^2</xliff:g> lydfiler?</item>
<item quantity="one">Vil du tillate at <xliff:g id="APP_NAME_0">^1</xliff:g> sletter denne lydfilen?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other">Sletter <xliff:g id="COUNT">^1</xliff:g> lydfiler …</item>
+ <item quantity="one">Sletter lydfilen …</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">Vil du tillate at <xliff:g id="APP_NAME_1">^1</xliff:g> sletter <xliff:g id="COUNT">^2</xliff:g> videoer?</item>
<item quantity="one">Vil du tillate at <xliff:g id="APP_NAME_0">^1</xliff:g> sletter denne videoen?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other">Sletter <xliff:g id="COUNT">^1</xliff:g> videoer …</item>
+ <item quantity="one">Sletter videoen …</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">Vil du tillate at <xliff:g id="APP_NAME_1">^1</xliff:g> sletter <xliff:g id="COUNT">^2</xliff:g> bilder?</item>
<item quantity="one">Vil du tillate at <xliff:g id="APP_NAME_0">^1</xliff:g> sletter dette bildet?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other">Sletter <xliff:g id="COUNT">^1</xliff:g> bilder …</item>
+ <item quantity="one">Sletter bildet …</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">Vil du tillate at <xliff:g id="APP_NAME_1">^1</xliff:g> sletter <xliff:g id="COUNT">^2</xliff:g> elementer?</item>
<item quantity="one">Vil du tillate at <xliff:g id="APP_NAME_0">^1</xliff:g> sletter dette elementet?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other">Sletter <xliff:g id="COUNT">^1</xliff:g> elementer …</item>
+ <item quantity="one">Sletter elementet …</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> kan ikke behandle mediefiler"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Behandlingen av mediene er avbrutt"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Feil under behandling av mediene"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Mediene er blitt behandlet"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Behandlingen av mediene er startet"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Mediene behandles …"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Avbryt"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Vent"</string>
</resources>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 8700dc1..166bf0e 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -27,7 +27,7 @@
<string name="root_documents" msgid="3829103301363849237">"कागजातहरू"</string>
<string name="permission_required" msgid="1460820436132943754">"यो वस्तु परिमार्जन गर्न वा मेटाउन अनुमति आवश्यक पर्छ।"</string>
<string name="permission_required_action" msgid="706370952366113539">"जारी राख्नुहोस्"</string>
- <string name="grant_dialog_button_allow" msgid="1644287024501033471">"अनुमति दिइयोस्"</string>
+ <string name="grant_dialog_button_allow" msgid="1644287024501033471">"अनुमति दिनुहोस्"</string>
<string name="grant_dialog_button_deny" msgid="6190589471415815741">"अनुमति नदिनुहोस्"</string>
<plurals name="permission_more_thumb" formatted="false" msgid="4392079224649478923">
<item quantity="other">+<xliff:g id="COUNT_1">^1</xliff:g></item>
@@ -47,64 +47,136 @@
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> लाई यी <xliff:g id="COUNT">^2</xliff:g> अडियो फाइलहरू परिमार्जन गर्न दिने हो?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> लाई यो अडियो फाइल परिमार्जन गर्न दिने हो?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> वटा अडियो फाइल परिमार्जन गरिँदै छन्…</item>
+ <item quantity="one">अडियो फाइल परिमार्जन गरिँदै छ…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> लाई यी <xliff:g id="COUNT">^2</xliff:g> भिडियोहरू परिमार्जन गर्न दिने हो?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> लाई यो भिडियो परिमार्जन गर्न दिने हो?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> वटा भिडियो परिमार्जन गरिँदै छन्…</item>
+ <item quantity="one">भिडियो परिमार्जन गरिँदै छ…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> लाई यी <xliff:g id="COUNT">^2</xliff:g> फोटोहरू परिमार्जन गर्न दिने हो?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> लाई यो फोटो परिमार्जन गर्न दिने हो?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> वटा फोटो परिमार्जन गरिँदै छन्…</item>
+ <item quantity="one">फोटो परिमार्जन गरिँदै छ…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> लाई यी <xliff:g id="COUNT">^2</xliff:g> वस्तुहरू परिमार्जन गर्न दिने हो?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> लाई यो वस्तु परिमार्जन गर्न दिने हो?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> वटा वस्तु परिमार्जन गरिँदै छन्…</item>
+ <item quantity="one">वस्तु परिमार्जन गरिँदै छ…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> लाई यी <xliff:g id="COUNT">^2</xliff:g> अडियो फाइलहरू सारेर रद्दीको टोकरीमा लैजान दिने हो?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> लाई यो अडियो फाइल सारेर रद्दीको टोकरीमा लैजान दिने हो?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> वटा अडियो फाइल सारेर ट्र्यासमा लगिँदै छन्…</item>
+ <item quantity="one">अडियो फाइल सारेर ट्र्यासमा लगिँदै छ…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> लाई यी <xliff:g id="COUNT">^2</xliff:g> भिडियोहरू सारेर रद्दीको टोकरीमा लैजान दिने हो?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> लाई यो भिडियो सारेर रद्दीको टोकरीमा लैजान दिने हो?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> वटा भिडियो सारेर ट्र्यासमा लगिँदै छन्…</item>
+ <item quantity="one">भिडियो सारेर ट्र्यासमा लगिँदै छ…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> लाई यी <xliff:g id="COUNT">^2</xliff:g> फोटोहरू सारेर रद्दीको टोकरीमा लैजान दिने हो?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> लाई यो फोटो सारेर रद्दीको टोकरीमा लैजान दिने हो?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> वटा फोटो सारेर ट्र्यासमा लगिँदै छन्…</item>
+ <item quantity="one">फोटो सारेर ट्र्यासमा लगिँदै छ…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> लाई यी <xliff:g id="COUNT">^2</xliff:g> वस्तुहरू सारेर रद्दीको टोकरीमा लैजान दिने हो?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> लाई यो वस्तु सारेर रद्दीको टोकरीमा लैजान दिने हो?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> वटा वस्तु सारेर ट्र्यासमा लगिँदै छन्…</item>
+ <item quantity="one">वस्तु सारेर ट्र्यासमा लगिँदै छ…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> लाई यी <xliff:g id="COUNT">^2</xliff:g> अडियो फाइलहरू रद्दीको टोकरीबाट निकालेर ल्याउन दिने हो?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> लाई यो अडियो फाइल रद्दीको टोकरीबाट निकालेर ल्याउन दिने हो?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other">ट्र्यासबाट <xliff:g id="COUNT">^1</xliff:g> वटा अडियो फाइल सारिँदै छन्…</item>
+ <item quantity="one">ट्र्यासबाट अडियो फाइल सारिँदै छ…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> लाई यी <xliff:g id="COUNT">^2</xliff:g> भिडियोहरू रद्दीको टोकरीबाट निकालेर ल्याउन दिने हो?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> लाई यो भिडियो रद्दीको टोकरीबाट निकालेर ल्याउन दिने हो?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other">ट्र्यासबाट <xliff:g id="COUNT">^1</xliff:g> वटा भिडियो सारिँदै छन्…</item>
+ <item quantity="one">ट्र्यासबाट भिडियो सारिँदै छ…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> लाई यी <xliff:g id="COUNT">^2</xliff:g> फोटोहरू रद्दीको टोकरीबाट निकालेर ल्याउन दिने हो?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> लाई यो फोटो रद्दीको टोकरीबाट निकालेर ल्याउन दिने हो?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other">ट्र्यासबाट <xliff:g id="COUNT">^1</xliff:g> वटा फोटो सारिँदै छन्…</item>
+ <item quantity="one">ट्र्यासबाट फोटो सारिँदै छ…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> लाई यी <xliff:g id="COUNT">^2</xliff:g> वस्तुहरू रद्दीको टोकरीबाट निकालेर ल्याउन दिने हो?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> लाई यो वस्तु रद्दीको टोकरीबाट निकालेर ल्याउन दिने हो?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other">ट्र्यासबाट <xliff:g id="COUNT">^1</xliff:g> वटा वस्तु सारिँदै छन्…</item>
+ <item quantity="one">ट्र्यासबाट वस्तु सारिँदै छ…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> लाई यी <xliff:g id="COUNT">^2</xliff:g> अडियो फाइलहरू मेटाउन दिने हो?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> लाई यो अडियो फाइल मेटाउन दिने हो?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> वटा अडियो फाइल मेटाइँदै छन्…</item>
+ <item quantity="one">अडियो फाइल मेटाइँदै छ…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> लाई यी <xliff:g id="COUNT">^2</xliff:g> भिडियोहरू मेटाउन दिने हो?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> लाई यो भिडियो मेटाउन दिने हो?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> वटा भिडियो मेटाइँदै छन्…</item>
+ <item quantity="one">भिडियो मेटाइँदै छ…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> लाई यी <xliff:g id="COUNT">^2</xliff:g> फोटोहरू मेटाउन दिने हो?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> लाई यो फोटो मेटाउन दिने हो?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> वटा फोटो मेटाइँदै छन्…</item>
+ <item quantity="one">फोटो मेटाइँदै छ…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> लाई यी <xliff:g id="COUNT">^2</xliff:g> वस्तुहरू मेटाउन दिने हो?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> लाई यो वस्तु मेटाउन दिने हो?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> वटा वस्तु मेटाइँदै छन्…</item>
+ <item quantity="one">वस्तु मेटाइँदै छ…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> ले मिडिया फाइलहरू प्रयोग गर्न सक्दैन"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"मिडिया प्रोसेस गर्ने कार्य रद्द गरियो"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"मिडिया प्रोसेस गर्ने क्रममा त्रुटि भयो"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"मिडिया प्रोसेस गरियो"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"मिडिया प्रोसेस गर्न थालियो"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"मिडिया प्रोसेस गरिँदै छ…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"रद्द गर्नुहोस्"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"पर्खनुहोस्"</string>
</resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index d685675..dcd8a36 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> toestaan <xliff:g id="COUNT">^2</xliff:g> audiobestanden te wijzigen?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> toestaan dit audiobestand te wijzigen?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> audiobestanden aanpassen…</item>
+ <item quantity="one">Audiobestand aanpassen…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> toestaan <xliff:g id="COUNT">^2</xliff:g> video\'s te wijzigen?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> toestaan deze video te wijzigen?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> video\'s aanpassen…</item>
+ <item quantity="one">Video aanpassen…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> toestaan <xliff:g id="COUNT">^2</xliff:g> foto\'s te wijzigen?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> toestaan deze foto te wijzigen?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> foto\'s aanpassen…</item>
+ <item quantity="one">Foto aanpassen…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> toestaan <xliff:g id="COUNT">^2</xliff:g> items te wijzigen?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> toestaan dit item te wijzigen?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> items aanpassen…</item>
+ <item quantity="one">Item aanpassen…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> toestaan <xliff:g id="COUNT">^2</xliff:g> audiobestanden naar de prullenbak te verplaatsen?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> toestaan dit audiobestand naar de prullenbak te verplaatsen?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> audiobestanden naar prullenbak verplaatsen…</item>
+ <item quantity="one">Audiobestand naar prullenbak verplaatsen…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> toestaan <xliff:g id="COUNT">^2</xliff:g> video\'s naar de prullenbak te verplaatsen?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> toestaan deze video naar de prullenbak te verplaatsen?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> video\'s naar prullenbak verplaatsen…</item>
+ <item quantity="one">Video naar prullenbak verplaatsen…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> toestaan <xliff:g id="COUNT">^2</xliff:g> foto\'s naar de prullenbak te verplaatsen?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> toestaan deze foto naar de prullenbak te verplaatsen?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> foto\'s naar prullenbak verplaatsen…</item>
+ <item quantity="one">Foto naar prullenbak verplaatsen…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> toestaan <xliff:g id="COUNT">^2</xliff:g> items naar de prullenbak te verplaatsen?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> toestaan dit item naar de prullenbak te verplaatsen?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> items naar prullenbak verplaatsen…</item>
+ <item quantity="one">Item naar prullenbak verplaatsen…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> toestaan <xliff:g id="COUNT">^2</xliff:g> audiobestanden uit de prullenbak te halen?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> toestaan dit audiobestand uit de prullenbak te halen?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> audiobestanden uit prullenbak halen…</item>
+ <item quantity="one">Audiobestand uit prullenbak halen…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> toestaan <xliff:g id="COUNT">^2</xliff:g> video\'s uit de prullenbak te halen?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> toestaan deze video uit de prullenbak te halen?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> video\'s uit prullenbak halen…</item>
+ <item quantity="one">Video uit prullenbak halen…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> toestaan <xliff:g id="COUNT">^2</xliff:g> foto\'s uit de prullenbak te halen?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> toestaan deze foto uit de prullenbak te halen?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> foto\'s uit prullenbak halen…</item>
+ <item quantity="one">Foto uit prullenbak halen…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> toestaan <xliff:g id="COUNT">^2</xliff:g> items uit de prullenbak te halen?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> toestaan dit item uit de prullenbak te halen?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> items uit prullenbak halen…</item>
+ <item quantity="one">Item uit prullenbak halen…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> toestaan <xliff:g id="COUNT">^2</xliff:g> audiobestanden te verwijderen?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> toestaan dit audiobestand te verwijderen?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> audiobestanden verwijderen…</item>
+ <item quantity="one">Audiobestand verwijderen…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> toestaan <xliff:g id="COUNT">^2</xliff:g> video\'s te verwijderen?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> toestaan deze video te verwijderen?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> video\'s verwijderen…</item>
+ <item quantity="one">Video verwijderen…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> toestaan <xliff:g id="COUNT">^2</xliff:g> foto\'s te verwijderen?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> toestaan deze foto te verwijderen?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> foto\'s verwijderen…</item>
+ <item quantity="one">Foto verwijderen…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> toestaan <xliff:g id="COUNT">^2</xliff:g> items te verwijderen?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> toestaan dit item te verwijderen?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> items verwijderen…</item>
+ <item quantity="one">Item verwijderen…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> kan geen mediabestanden verwerken"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Mediaverwerking geannuleerd"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Fout bij mediaverwerking"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Mediaverwerking afgerond"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Mediaverwerking gestart"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Media verwerken…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Annuleren"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Wachten"</string>
</resources>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 5ea6ea3..1e185dc 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g>ଟି ଅଡିଓ ଫାଇଲକୁ ପରିବର୍ତ୍ତନ କରିବା ପାଇଁ <xliff:g id="APP_NAME_1">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
<item quantity="one">ଏହି ଅଡିଓ ଫାଇଲକୁ ପରିବର୍ତ୍ତନ କରିବା ପାଇଁ <xliff:g id="APP_NAME_0">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>ଟି ଅଡିଓ ଫାଇଲ୍ ପରିବର୍ତ୍ତନ କରାଯାଉଛି…</item>
+ <item quantity="one">ଅଡିଓ ଫାଇଲ୍ ପରିବର୍ତ୍ତନ କରାଯାଉଛି…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g>ଟି ଭିଡିଓକୁ ପରିବର୍ତ୍ତନ କରିବା ପାଇଁ <xliff:g id="APP_NAME_1">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
<item quantity="one">ଏହି ଭିଡିଓକୁ ପରିବର୍ତ୍ତନ କରିବା ପାଇଁ <xliff:g id="APP_NAME_0">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>ଟି ଭିଡିଓ ପରିବର୍ତ୍ତନ କରାଯାଉଛି…</item>
+ <item quantity="one">ଭିଡିଓ ପରିବର୍ତ୍ତନ କରାଯାଉଛି…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g>ଟି ଫଟୋ ପରିବର୍ତ୍ତନ କରିବା ପାଇଁ <xliff:g id="APP_NAME_1">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
<item quantity="one">ଏହି ଫଟୋକୁ ପରିବର୍ତ୍ତନ କରିବା ପାଇଁ <xliff:g id="APP_NAME_0">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>ଟି ଫଟୋ ପରିବର୍ତ୍ତନ କରାଯାଉଛି…</item>
+ <item quantity="one">ଫଟୋ ପରିବର୍ତ୍ତନ କରାଯାଉଛି…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g>ଟି ଆଇଟମକୁ ପରିବର୍ତ୍ତନ କରିବା ପାଇଁ <xliff:g id="APP_NAME_1">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
<item quantity="one">ଏହି ଆଇଟମକୁ ପରିବର୍ତ୍ତନ କରିବା ପାଇଁ <xliff:g id="APP_NAME_0">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>ଟି ଆଇଟମ୍ ପରିବର୍ତ୍ତନ କରାଯାଉଛି…</item>
+ <item quantity="one">ଆଇଟମ୍ ପରିବର୍ତ୍ତନ କରାଯାଉଛି…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g>ଟି ଅଡିଓ ଫାଇଲକୁ ଟ୍ରାସକୁ ମୁଭ୍ କରିବା ପାଇଁ <xliff:g id="APP_NAME_1">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
<item quantity="one">ଏହି ଅଡିଓ ଫାଇଲକୁ ଟ୍ରାସକୁ ମୁଭ୍ କରିବା ପାଇଁ <xliff:g id="APP_NAME_0">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>ଟି ଅଡିଓ ଫାଇଲ୍ ଟ୍ରାସକୁ ମୁଭ୍ କରାଯାଉଛି…</item>
+ <item quantity="one">ଅଡିଓ ଫାଇଲ୍ ଟ୍ରାସକୁ ମୁଭ୍ କରାଯାଉଛି…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g>ଟି ଭିଡିଓକୁ ଟ୍ରାସକୁ ମୁଭ୍ କରିବା ପାଇଁ <xliff:g id="APP_NAME_1">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
<item quantity="one">ଏହି ଭିଡିଓକୁ ଟ୍ରାସକୁ ମୁଭ୍ କରିବା ପାଇଁ <xliff:g id="APP_NAME_0">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>ଟି ଭିଡିଓ ଟ୍ରାସକୁ ମୁଭ୍ କରାଯାଉଛି…</item>
+ <item quantity="one">ଭିଡିଓ ଟ୍ରାସକୁ ମୁଭ୍ କରାଯାଉଛି…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g>ଟି ଫଟୋକୁ ଟ୍ରାସକୁ ମୁଭ୍ କରିବା ପାଇଁ <xliff:g id="APP_NAME_1">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
<item quantity="one">ଏହି ଫଟୋକୁ ଟାସକୁ ମୁଭ୍ କରିବା ପାଇଁ <xliff:g id="APP_NAME_0">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>ଟି ଫଟୋ ଟ୍ରାସକୁ ମୁଭ୍ କରାଯାଉଛି…</item>
+ <item quantity="one">ଫଟୋ ଟ୍ରାସକୁ ମୁଭ୍ କରାଯାଉଛି…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g>ଟି ଆଇଟମକୁ ଟ୍ରାସକୁ ମୁଭ୍ କରିବା ପାଇଁ <xliff:g id="APP_NAME_1">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
<item quantity="one">ଏହି ଆଇଟମକୁ ଟ୍ରାସକୁ ମୁଭ୍ କରିବା ପାଇଁ <xliff:g id="APP_NAME_0">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>ଟି ଆଇଟମ୍ ଟ୍ରାସକୁ ମୁଭ୍ କରାଯାଉଛି…</item>
+ <item quantity="one">ଆଇଟମ୍ ଟ୍ରାସକୁ ମୁଭ୍ କରାଯାଉଛି…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g>ଟି ଅଡିଓ ଫାଇଲକୁ ଟ୍ରାସରୁ ବାହାର କରିବା ପାଇଁ <xliff:g id="APP_NAME_1">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
<item quantity="one">ଏହି ଅଡିଓ ଫାଇଲକୁ ଟ୍ରାସରୁ ବାହାର କରିବା ପାଇଁ <xliff:g id="APP_NAME_0">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>ଟି ଅଡିଓ ଫାଇଲକୁ ଟ୍ରାସରୁ ମୁଭ୍ କରାଯାଉଛି…</item>
+ <item quantity="one">ଅଡିଓ ଫାଇଲକୁ ଟ୍ରାସରୁ ମୁଭ୍ କରାଯାଉଛି…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g>ଟି ଭିଡିଓକୁ ଟ୍ରାସରୁ ବାହାର କରିବା ପାଇଁ <xliff:g id="APP_NAME_1">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
<item quantity="one">ଏହି ଭିଡିଓକୁ ଟ୍ରାସରୁ ବାହାର କରିବା ପାଇଁ <xliff:g id="APP_NAME_0">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>ଟି ଭିଡିଓକୁ ଟ୍ରାସରୁ ମୁଭ୍ କରାଯାଉଛି…</item>
+ <item quantity="one">ଭିଡିଓକୁ ଟ୍ରାସରୁ ମୁଭ୍ କରାଯାଉଛି…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g>ଟି ଫଟୋକୁ ଟ୍ରାସରୁ ବାହାର କରିବା ପାଇଁ <xliff:g id="APP_NAME_1">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
<item quantity="one">ଏହି ଫଟୋକୁ ଟ୍ରାସରୁ ବାହାର କରିବା ପାଇଁ <xliff:g id="APP_NAME_0">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>ଟି ଫଟୋକୁ ଟ୍ରାସରୁ ମୁଭ୍ କରାଯାଉଛି…</item>
+ <item quantity="one">ଫଟୋକୁ ଟ୍ରାସରୁ ମୁଭ୍ କରାଯାଉଛି…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g>ଟି ଆଇଟମକୁ ଟ୍ରାସରୁ ବାହାର କରିବା ପାଇଁ <xliff:g id="APP_NAME_1">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
<item quantity="one">ଏହି ଆଇଟମକୁ ଟ୍ରାସରୁ ବାହାର କରିବା ପାଇଁ <xliff:g id="APP_NAME_0">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>ଟି ଆଇଟମକୁ ଟ୍ରାସରୁ ମୁଭ୍ କରାଯାଉଛି…</item>
+ <item quantity="one">ଆଇଟମକୁ ଟ୍ରାସରୁ ମୁଭ୍ କରାଯାଉଛି…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g>ଟି ଅଡିଓ ଫାଇଲକୁ ଡିଲିଟ୍ କରିବାକୁ <xliff:g id="APP_NAME_1">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
<item quantity="one">ଏହି ଅଡିଓ ଫାଇଲକୁ ଡିଲିଟ୍ କରିବାକୁ <xliff:g id="APP_NAME_0">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>ଟି ଅଡିଓ ଫାଇଲ୍ ଡିଲିଟ୍ କରାଯାଉଛି…</item>
+ <item quantity="one">ଅଡିଓ ଫାଇଲ୍ ଡିଲିଟ୍ କରାଯାଉଛି…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g>ଟି ଭିଡିଓକୁ ଡିଲିଟ୍ କରିବାକୁ <xliff:g id="APP_NAME_1">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
<item quantity="one">ଏହି ଭିଡିଓକୁ ଡିଲିଟ୍ କରିବାକୁ <xliff:g id="APP_NAME_0">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>ଟି ଭିଡିଓ ଡିଲିଟ୍ କରାଯାଉଛି…</item>
+ <item quantity="one">ଭିଡିଓ ଡିଲିଟ୍ କରାଯାଉଛି…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g>ଟି ଫଟୋକୁ ଡିଲିଟ୍ କରିବାକୁ <xliff:g id="APP_NAME_1">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
<item quantity="one">ଏହି ଫଟୋକୁ ଡିଲିଟ୍ କରିବାକୁ <xliff:g id="APP_NAME_0">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>ଟି ଫଟୋ ଡିଲିଟ୍ କରାଯାଉଛି…</item>
+ <item quantity="one">ଫଟୋ ଡିଲିଟ୍ କରାଯାଉଛି…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g>ଟି ଆଇଟମକୁ ଡିଲିଟ୍ କରିବାକୁ <xliff:g id="APP_NAME_1">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
<item quantity="one">ଏହି ଆଇଟମକୁ ଡିଲିଟ୍ କରିବାକୁ <xliff:g id="APP_NAME_0">^1</xliff:g>କୁ ଅନୁମତି ଦେବେ?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>ଟି ଆଇଟମ୍ ଡିଲିଟ୍ କରାଯାଉଛି…</item>
+ <item quantity="one">ଆଇଟମ୍ ଡିଲିଟ୍ କରାଯାଉଛି…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> ମିଡିଆ ଫାଇଲଗୁଡ଼ିକୁ ପ୍ରକ୍ରିୟାନ୍ୱିତ କରିପାରିବ ନାହିଁ"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"ମିଡିଆ ପ୍ରକ୍ରିୟାକରଣ ବାତିଲ୍ କରାଯାଇଛି"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"ମିଡିଆ ପ୍ରକ୍ରିୟାକରଣ ତ୍ରୁଟି"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"ମିଡିଆ ପ୍ରକ୍ରିୟାକରଣ ସଫଳ ହୋଇଛି"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"ମିଡିଆ ପ୍ରକ୍ରିୟାକରଣ ଆରମ୍ଭ କରାଯାଇଛି"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"ମିଡିଆ ପ୍ରକ୍ରିୟାକରଣ କରାଯାଉଛି…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"ବାତିଲ୍ କରନ୍ତୁ"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"ଅପେକ୍ଷା କରନ୍ତୁ"</string>
</resources>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index cb5e9b4..273c6b6 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -47,64 +47,136 @@
<item quantity="one">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਆਡੀਓ ਫ਼ਾਈਲ ਨੂੰ ਸੋਧਣ ਦੇਣਾ ਹੈ?</item>
<item quantity="other">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਆਡੀਓ ਫ਼ਾਈਲਾਂ ਨੂੰ ਸੋਧਣ ਦੇਣਾ ਹੈ?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ਆਡੀਓ ਫ਼ਾਈਲ ਸੋਧੀ ਜਾ ਰਹੀ ਹੈ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ਆਡੀਓ ਫ਼ਾਈਲਾਂ ਸੋਧੀਆਂ ਜਾ ਰਹੀਆਂ ਹਨ…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="one">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਵੀਡੀਓ ਨੂੰ ਸੋਧਣ ਦੇਣਾ ਹੈ?</item>
<item quantity="other">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਵੀਡੀਓ ਨੂੰ ਸੋਧਣ ਦੇਣਾ ਹੈ?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ਵੀਡੀਓ ਸੋਧਿਆ ਜਾ ਰਿਹਾ ਹੈ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ਵੀਡੀਓ ਸੋਧੇ ਜਾ ਰਹੇ ਹਨ…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="one">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਫ਼ੋਟੋ ਨੂੰ ਸੋਧਣ ਦੇਣਾ ਹੈ?</item>
<item quantity="other">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਫ਼ੋਟੋਆਂ ਨੂੰ ਸੋਧਣ ਦੇਣਾ ਹੈ?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ਫ਼ੋਟੋ ਸੋਧੀ ਜਾ ਰਹੀ ਹੈ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ਫ਼ੋਟੋਆਂ ਸੋਧੀਆਂ ਜਾ ਰਹੀਆਂ ਹਨ…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="one">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਆਈਟਮ ਨੂੰ ਸੋਧਣ ਦੇਣਾ ਹੈ?</item>
<item quantity="other">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਆਈਟਮਾਂ ਨੂੰ ਸੋਧਣ ਦੇਣਾ ਹੈ?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ਆਈਟਮ ਸੋਧੀ ਜਾ ਰਹੀ ਹੈ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ਆਈਟਮਾਂ ਸੋਧੀਆਂ ਜਾ ਰਹੀਆਂ ਹਨ…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="one">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਆਡੀਓ ਫ਼ਾਈਲ ਨੂੰ ਰੱਦੀ ਵਿੱਚ ਲਿਜਾਣ ਦੇਣਾ ਹੈ?</item>
<item quantity="other">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਆਡੀਓ ਫ਼ਾਈਲਾਂ ਨੂੰ ਰੱਦੀ ਵਿੱਚ ਲਿਜਾਣ ਦੇਣਾ ਹੈ?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ਆਡੀਓ ਫ਼ਾਈਲ ਰੱਦੀ ਵਿੱਚ ਲਿਜਾਈ ਜਾ ਰਹੀ ਹੈ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ਆਡੀਓ ਫ਼ਾਈਲਾਂ ਰੱਦੀ ਵਿੱਚ ਲਿਜਾਈਆਂ ਜਾ ਰਹੀਆਂ ਹਨ…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="one">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਵੀਡੀਓ ਨੂੰ ਰੱਦੀ ਵਿੱਚ ਲਿਜਾਣ ਦੇਣਾ ਹੈ?</item>
<item quantity="other">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਵੀਡੀਓ ਨੂੰ ਰੱਦੀ ਵਿੱਚ ਲਿਜਾਣ ਦੇਣਾ ਹੈ?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ਵੀਡੀਓ ਰੱਦੀ ਵਿੱਚ ਲਿਜਾਇਆ ਜਾ ਰਿਹਾ ਹੈ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ਵੀਡੀਓ ਰੱਦੀ ਵਿੱਚ ਲਿਜਾਏ ਜਾ ਰਹੇ ਹਨ…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="one">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਫ਼ੋਟੋ ਨੂੰ ਰੱਦੀ ਵਿੱਚ ਲਿਜਾਣ ਦੇਣਾ ਹੈ?</item>
<item quantity="other">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਫ਼ੋਟੋਆਂ ਨੂੰ ਰੱਦੀ ਵਿੱਚ ਲਿਜਾਣ ਦੇਣਾ ਹੈ?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ਫ਼ੋਟੋ ਰੱਦੀ ਵਿੱਚ ਲਿਜਾਈ ਜਾ ਰਹੀ ਹੈ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ਫ਼ੋਟੋਆਂ ਰੱਦੀ ਵਿੱਚ ਲਿਜਾਈਆਂ ਜਾ ਰਹੀਆਂ ਹਨ…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="one">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਆਈਟਮ ਨੂੰ ਰੱਦੀ ਵਿੱਚ ਲਿਜਾਣ ਦੇਣਾ ਹੈ?</item>
<item quantity="other">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਆਈਟਮਾਂ ਨੂੰ ਰੱਦੀ ਵਿੱਚ ਲਿਜਾਣ ਦੇਣਾ ਹੈ?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ਆਈਟਮ ਰੱਦੀ ਵਿੱਚ ਲਿਜਾਈ ਜਾ ਰਹੀ ਹੈ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ਆਈਟਮਾਂ ਰੱਦੀ ਵਿੱਚ ਲਿਜਾਈਆਂ ਜਾ ਰਹੀਆਂ ਹਨ…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="one">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਆਡੀਓ ਫ਼ਾਈਲ ਨੂੰ ਰੱਦੀ ਤੋਂ ਬਾਹਰ ਲਿਜਾਣ ਦੇਣਾ ਹੈ?</item>
<item quantity="other">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਆਡੀਓ ਫ਼ਾਈਲਾਂ ਨੂੰ ਰੱਦੀ ਤੋਂ ਬਾਹਰ ਲਿਜਾਣ ਦੇਣਾ ਹੈ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ਆਡੀਓ ਫ਼ਾਈਲ ਰੱਦੀ ਤੋਂ ਬਾਹਰ ਲਿਜਾਈ ਜਾ ਰਹੀ ਹੈ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ਆਡੀਓ ਫ਼ਾਈਲਾਂ ਰੱਦੀ ਤੋਂ ਬਾਹਰ ਲਿਜਾਈਆਂ ਜਾ ਰਹੀਆਂ ਹਨ…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="one">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਵੀਡੀਓ ਨੂੰ ਰੱਦੀ ਤੋਂ ਬਾਹਰ ਲਿਜਾਣ ਦੇਣਾ ਹੈ?</item>
<item quantity="other">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਵੀਡੀਓ ਨੂੰ ਰੱਦੀ ਤੋਂ ਬਾਹਰ ਲਿਜਾਣ ਦੇਣਾ ਹੈ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ਵੀਡੀਓ ਰੱਦੀ ਤੋਂ ਬਾਹਰ ਲਿਜਾਇਆ ਜਾ ਰਿਹਾ ਹੈ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ਵੀਡੀਓ ਰੱਦੀ ਤੋਂ ਬਾਹਰ ਲਿਜਾਏ ਜਾ ਰਹੇ ਹਨ…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="one">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਫ਼ੋਟੋ ਨੂੰ ਰੱਦੀ ਤੋਂ ਬਾਹਰ ਲਿਜਾਣ ਦੇਣਾ ਹੈ?</item>
<item quantity="other">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਫ਼ੋਟੋਆਂ ਨੂੰ ਰੱਦੀ ਤੋਂ ਬਾਹਰ ਲਿਜਾਣ ਦੇਣਾ ਹੈ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ਫ਼ੋਟੋ ਰੱਦੀ ਤੋਂ ਬਾਹਰ ਲਿਜਾਈ ਜਾ ਰਹੀ ਹੈ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ਫ਼ੋਟੋਆਂ ਰੱਦੀ ਤੋਂ ਬਾਹਰ ਲਿਜਾਈਆਂ ਜਾ ਰਹੀਆਂ ਹਨ…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="one">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਆਈਟਮ ਨੂੰ ਰੱਦੀ ਤੋਂ ਬਾਹਰ ਲਿਜਾਣ ਦੇਣਾ ਹੈ?</item>
<item quantity="other">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਆਈਟਮਾਂ ਨੂੰ ਰੱਦੀ ਤੋਂ ਬਾਹਰ ਲਿਜਾਣ ਦੇਣਾ ਹੈ?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ਆਈਟਮ ਰੱਦੀ ਤੋਂ ਬਾਹਰ ਲਿਜਾਈ ਜਾ ਰਹੀ ਹੈ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ਆਈਟਮਾਂ ਰੱਦੀ ਤੋਂ ਬਾਹਰ ਲਿਜਾਈਆਂ ਜਾ ਰਹੀਆਂ ਹਨ…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="one">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਆਡੀਓ ਫ਼ਾਈਲ ਨੂੰ ਮਿਟਾਉਣ ਦੇਣਾ ਹੈ?</item>
<item quantity="other">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਆਡੀਓ ਫ਼ਾਈਲਾਂ ਨੂੰ ਮਿਟਾਉਣ ਦੇਣਾ ਹੈ?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ਆਡੀਓ ਫ਼ਾਈਲ ਮਿਟਾਈ ਜਾ ਰਹੀ ਹੈ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ਆਡੀਓ ਫ਼ਾਈਲਾਂ ਮਿਟਾਈਆਂ ਜਾ ਰਹੀਆਂ ਹਨ…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="one">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਵੀਡੀਓ ਨੂੰ ਮਿਟਾਉਣ ਦੇਣਾ ਹੈ?</item>
<item quantity="other">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਵੀਡੀਓ ਨੂੰ ਮਿਟਾਉਣ ਦੇਣਾ ਹੈ?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ਵੀਡੀਓ ਮਿਟਾਇਆ ਜਾ ਰਿਹਾ ਹੈ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ਵੀਡੀਓ ਮਿਟਾਏ ਜਾ ਰਹੇ ਹਨ…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="one">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਫ਼ੋਟੋ ਨੂੰ ਮਿਟਾਉਣ ਦੇਣਾ ਹੈ?</item>
<item quantity="other">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਫ਼ੋਟੋਆਂ ਨੂੰ ਮਿਟਾਉਣ ਦੇਣਾ ਹੈ?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ਫ਼ੋਟੋ ਮਿਟਾਈ ਜਾ ਰਹੀ ਹੈ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ਫ਼ੋਟੋਆਂ ਮਿਟਾਈਆਂ ਜਾ ਰਹੀਆਂ ਹਨ…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="one">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਆਈਟਮ ਨੂੰ ਮਿਟਾਉਣ ਦੇਣਾ ਹੈ?</item>
<item quantity="other">ਕੀ <xliff:g id="APP_NAME_1">^1</xliff:g> ਨੂੰ <xliff:g id="COUNT">^2</xliff:g> ਆਈਟਮਾਂ ਨੂੰ ਮਿਟਾਉਣ ਦੇਣਾ ਹੈ?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ਆਈਟਮ ਮਿਟਾਈ ਜਾ ਰਹੀ ਹੈ…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ਆਈਟਮਾਂ ਮਿਟਾਈਆਂ ਜਾ ਰਹੀਆਂ ਹਨ…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> ਐਪ ਮੀਡੀਆ ਫ਼ਾਈਲਾਂ \'ਤੇ ਪ੍ਰਕਿਰਿਆ ਨਹੀਂ ਕਰ ਸਕਦੀ"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"ਮੀਡੀਆ \'ਤੇ ਪ੍ਰਕਿਰਿਆ ਨੂੰ ਰੱਦ ਕੀਤਾ ਗਿਆ"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"ਮੀਡੀਆ \'ਤੇ ਪ੍ਰਕਿਰਿਆ ਸੰਬੰਧੀ ਗੜਬੜ"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"ਮੀਡੀਆ \'ਤੇ ਪ੍ਰਕਿਰਿਆ ਸਫਲ ਰਹੀ"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"ਮੀਡੀਆ \'ਤੇ ਪ੍ਰਕਿਰਿਆ ਨੂੰ ਸ਼ੁਰੂ ਕੀਤਾ ਗਿਆ"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"ਮੀਡੀਆ \'ਤੇ ਪ੍ਰਕਿਰਿਆ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"ਰੱਦ ਕਰੋ"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"ਉਡੀਕ ਕਰੋ"</string>
</resources>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index ea4a8ce..d308c74 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -53,94 +53,198 @@
<item quantity="other">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na zmodyfikowanie <xliff:g id="COUNT">^2</xliff:g> pliku audio?</item>
<item quantity="one">Zezwolić aplikacji <xliff:g id="APP_NAME_0">^1</xliff:g> na zmodyfikowanie tego pliku audio?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="few">Modyfikuję <xliff:g id="COUNT">^1</xliff:g> pliki audio…</item>
+ <item quantity="many">Modyfikuję <xliff:g id="COUNT">^1</xliff:g> plików audio…</item>
+ <item quantity="other">Modyfikuję <xliff:g id="COUNT">^1</xliff:g> pliku audio…</item>
+ <item quantity="one">Modyfikuję plik audio…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="few">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na zmodyfikowanie <xliff:g id="COUNT">^2</xliff:g> filmów?</item>
<item quantity="many">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na zmodyfikowanie <xliff:g id="COUNT">^2</xliff:g> filmów?</item>
<item quantity="other">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na zmodyfikowanie <xliff:g id="COUNT">^2</xliff:g> filmu?</item>
<item quantity="one">Zezwolić aplikacji <xliff:g id="APP_NAME_0">^1</xliff:g> na zmodyfikowanie tego filmu?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="few">Modyfikuję <xliff:g id="COUNT">^1</xliff:g> filmy…</item>
+ <item quantity="many">Modyfikuję <xliff:g id="COUNT">^1</xliff:g> filmów…</item>
+ <item quantity="other">Modyfikuję <xliff:g id="COUNT">^1</xliff:g> filmu…</item>
+ <item quantity="one">Modyfikuję film…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="few">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na zmodyfikowanie <xliff:g id="COUNT">^2</xliff:g> zdjęć?</item>
<item quantity="many">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na zmodyfikowanie <xliff:g id="COUNT">^2</xliff:g> zdjęć?</item>
<item quantity="other">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na zmodyfikowanie <xliff:g id="COUNT">^2</xliff:g> zdjęcia?</item>
<item quantity="one">Zezwolić aplikacji <xliff:g id="APP_NAME_0">^1</xliff:g> na zmodyfikowanie tego zdjęcia?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="few">Modyfikuję <xliff:g id="COUNT">^1</xliff:g> zdjęcia…</item>
+ <item quantity="many">Modyfikuję <xliff:g id="COUNT">^1</xliff:g> zdjęć…</item>
+ <item quantity="other">Modyfikuję <xliff:g id="COUNT">^1</xliff:g> zdjęcia…</item>
+ <item quantity="one">Modyfikuję zdjęcie…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="few">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na zmodyfikowanie <xliff:g id="COUNT">^2</xliff:g> elementów?</item>
<item quantity="many">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na zmodyfikowanie <xliff:g id="COUNT">^2</xliff:g> elementów?</item>
<item quantity="other">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na zmodyfikowanie <xliff:g id="COUNT">^2</xliff:g> elementu?</item>
<item quantity="one">Zezwolić aplikacji <xliff:g id="APP_NAME_0">^1</xliff:g> na zmodyfikowanie tego elementu?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="few">Modyfikuję <xliff:g id="COUNT">^1</xliff:g> elementy…</item>
+ <item quantity="many">Modyfikuję <xliff:g id="COUNT">^1</xliff:g> elementów…</item>
+ <item quantity="other">Modyfikuję <xliff:g id="COUNT">^1</xliff:g> elementu…</item>
+ <item quantity="one">Modyfikuję element…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="few">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na przeniesienie <xliff:g id="COUNT">^2</xliff:g> plików audio do kosza?</item>
<item quantity="many">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na przeniesienie <xliff:g id="COUNT">^2</xliff:g> plików audio do kosza?</item>
<item quantity="other">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na przeniesienie <xliff:g id="COUNT">^2</xliff:g> pliku audio do kosza?</item>
<item quantity="one">Zezwolić aplikacji <xliff:g id="APP_NAME_0">^1</xliff:g> na przeniesienie tego pliku audio do kosza?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="few">Przenoszę <xliff:g id="COUNT">^1</xliff:g> pliki audio do kosza…</item>
+ <item quantity="many">Przenoszę <xliff:g id="COUNT">^1</xliff:g> plików audio do kosza…</item>
+ <item quantity="other">Przenoszę <xliff:g id="COUNT">^1</xliff:g> pliku audio do kosza…</item>
+ <item quantity="one">Przenoszę plik audio do kosza…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="few">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na przeniesienie <xliff:g id="COUNT">^2</xliff:g> filmów do kosza?</item>
<item quantity="many">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na przeniesienie <xliff:g id="COUNT">^2</xliff:g> filmów do kosza?</item>
<item quantity="other">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na przeniesienie <xliff:g id="COUNT">^2</xliff:g> filmu do kosza?</item>
<item quantity="one">Zezwolić aplikacji <xliff:g id="APP_NAME_0">^1</xliff:g> na przeniesienie tego filmu do kosza?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="few">Przenoszę <xliff:g id="COUNT">^1</xliff:g> filmy do kosza…</item>
+ <item quantity="many">Przenoszę <xliff:g id="COUNT">^1</xliff:g> filmów do kosza…</item>
+ <item quantity="other">Przenoszę <xliff:g id="COUNT">^1</xliff:g> filmu do kosza…</item>
+ <item quantity="one">Przenoszę film do kosza…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="few">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na przeniesienie <xliff:g id="COUNT">^2</xliff:g> zdjęć do kosza?</item>
<item quantity="many">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na przeniesienie <xliff:g id="COUNT">^2</xliff:g> zdjęć do kosza?</item>
<item quantity="other">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na przeniesienie <xliff:g id="COUNT">^2</xliff:g> zdjęcia do kosza?</item>
<item quantity="one">Zezwolić aplikacji <xliff:g id="APP_NAME_0">^1</xliff:g> na przeniesienie tego zdjęcia do kosza?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="few">Przenoszę <xliff:g id="COUNT">^1</xliff:g> zdjęcia do kosza…</item>
+ <item quantity="many">Przenoszę <xliff:g id="COUNT">^1</xliff:g> zdjęć do kosza…</item>
+ <item quantity="other">Przenoszę <xliff:g id="COUNT">^1</xliff:g> zdjęcia do kosza…</item>
+ <item quantity="one">Przenoszę zdjęcie do kosza…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="few">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na przeniesienie <xliff:g id="COUNT">^2</xliff:g> elementów do kosza?</item>
<item quantity="many">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na przeniesienie <xliff:g id="COUNT">^2</xliff:g> elementów do kosza?</item>
<item quantity="other">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na przeniesienie <xliff:g id="COUNT">^2</xliff:g> elementu do kosza?</item>
<item quantity="one">Zezwolić aplikacji <xliff:g id="APP_NAME_0">^1</xliff:g> na przeniesienie tego elementu do kosza?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="few">Przenoszę <xliff:g id="COUNT">^1</xliff:g> elementy do kosza…</item>
+ <item quantity="many">Przenoszę <xliff:g id="COUNT">^1</xliff:g> elementów do kosza…</item>
+ <item quantity="other">Przenoszę <xliff:g id="COUNT">^1</xliff:g> elementu do kosza…</item>
+ <item quantity="one">Przenoszę element do kosza…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="few">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na przeniesienie <xliff:g id="COUNT">^2</xliff:g> plików audio z kosza?</item>
<item quantity="many">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na przeniesienie <xliff:g id="COUNT">^2</xliff:g> plików audio z kosza?</item>
<item quantity="other">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na przeniesienie <xliff:g id="COUNT">^2</xliff:g> pliku audio z kosza?</item>
<item quantity="one">Zezwolić aplikacji <xliff:g id="APP_NAME_0">^1</xliff:g> na przeniesienie tego pliku audio z kosza?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="few">Przenoszę <xliff:g id="COUNT">^1</xliff:g> pliki audio z kosza…</item>
+ <item quantity="many">Przenoszę <xliff:g id="COUNT">^1</xliff:g> plików audio z kosza…</item>
+ <item quantity="other">Przenoszę <xliff:g id="COUNT">^1</xliff:g> pliku audio z kosza…</item>
+ <item quantity="one">Przenoszę plik audio z kosza…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="few">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na przeniesienie <xliff:g id="COUNT">^2</xliff:g> filmów z kosza?</item>
<item quantity="many">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na przeniesienie <xliff:g id="COUNT">^2</xliff:g> filmów z kosza?</item>
<item quantity="other">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na przeniesienie <xliff:g id="COUNT">^2</xliff:g> filmu z kosza?</item>
<item quantity="one">Zezwolić aplikacji <xliff:g id="APP_NAME_0">^1</xliff:g> na przeniesienie tego filmu z kosza?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="few">Przenoszę <xliff:g id="COUNT">^1</xliff:g> filmy z kosza…</item>
+ <item quantity="many">Przenoszę <xliff:g id="COUNT">^1</xliff:g> filmów z kosza…</item>
+ <item quantity="other">Przenoszę <xliff:g id="COUNT">^1</xliff:g> filmu z kosza…</item>
+ <item quantity="one">Przenoszę film z kosza…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="few">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na przeniesienie <xliff:g id="COUNT">^2</xliff:g> zdjęć z kosza?</item>
<item quantity="many">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na przeniesienie <xliff:g id="COUNT">^2</xliff:g> zdjęć z kosza?</item>
<item quantity="other">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na przeniesienie <xliff:g id="COUNT">^2</xliff:g> zdjęcia z kosza?</item>
<item quantity="one">Zezwolić aplikacji <xliff:g id="APP_NAME_0">^1</xliff:g> na przeniesienie tego zdjęcia z kosza?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="few">Przenoszę <xliff:g id="COUNT">^1</xliff:g> zdjęcia z kosza…</item>
+ <item quantity="many">Przenoszę <xliff:g id="COUNT">^1</xliff:g> zdjęć z kosza…</item>
+ <item quantity="other">Przenoszę <xliff:g id="COUNT">^1</xliff:g> zdjęcia z kosza…</item>
+ <item quantity="one">Przenoszę zdjęcie z kosza…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="few">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na przeniesienie <xliff:g id="COUNT">^2</xliff:g> elementów z kosza?</item>
<item quantity="many">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na przeniesienie <xliff:g id="COUNT">^2</xliff:g> elementów z kosza?</item>
<item quantity="other">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na przeniesienie <xliff:g id="COUNT">^2</xliff:g> elementu z kosza?</item>
<item quantity="one">Zezwolić aplikacji <xliff:g id="APP_NAME_0">^1</xliff:g> na przeniesienie tego elementu z kosza?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="few">Przenoszę <xliff:g id="COUNT">^1</xliff:g> elementy z kosza…</item>
+ <item quantity="many">Przenoszę <xliff:g id="COUNT">^1</xliff:g> elementów z kosza…</item>
+ <item quantity="other">Przenoszę <xliff:g id="COUNT">^1</xliff:g> elementu z kosza…</item>
+ <item quantity="one">Przenoszę element z kosza…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="few">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na usunięcie <xliff:g id="COUNT">^2</xliff:g> plików audio?</item>
<item quantity="many">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na usunięcie <xliff:g id="COUNT">^2</xliff:g> plików audio?</item>
<item quantity="other">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na usunięcie <xliff:g id="COUNT">^2</xliff:g> pliku audio?</item>
<item quantity="one">Zezwolić aplikacji <xliff:g id="APP_NAME_0">^1</xliff:g> na usunięcie tego pliku audio?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="few">Usuwam <xliff:g id="COUNT">^1</xliff:g> pliki audio…</item>
+ <item quantity="many">Usuwam <xliff:g id="COUNT">^1</xliff:g> plików audio…</item>
+ <item quantity="other">Usuwam <xliff:g id="COUNT">^1</xliff:g> pliku audio…</item>
+ <item quantity="one">Usuwam plik audio…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="few">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na usunięcie <xliff:g id="COUNT">^2</xliff:g> filmów?</item>
<item quantity="many">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na usunięcie <xliff:g id="COUNT">^2</xliff:g> filmów?</item>
<item quantity="other">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na usunięcie <xliff:g id="COUNT">^2</xliff:g> filmu?</item>
<item quantity="one">Zezwolić aplikacji <xliff:g id="APP_NAME_0">^1</xliff:g> na usunięcie tego filmu?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="few">Usuwam <xliff:g id="COUNT">^1</xliff:g> filmy…</item>
+ <item quantity="many">Usuwam <xliff:g id="COUNT">^1</xliff:g> filmów…</item>
+ <item quantity="other">Usuwam <xliff:g id="COUNT">^1</xliff:g> filmu…</item>
+ <item quantity="one">Usuwam film…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="few">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na usunięcie <xliff:g id="COUNT">^2</xliff:g> zdjęć?</item>
<item quantity="many">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na usunięcie <xliff:g id="COUNT">^2</xliff:g> zdjęć?</item>
<item quantity="other">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na usunięcie <xliff:g id="COUNT">^2</xliff:g> zdjęcia?</item>
<item quantity="one">Zezwolić aplikacji <xliff:g id="APP_NAME_0">^1</xliff:g> na usunięcie tego zdjęcia?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="few">Usuwam <xliff:g id="COUNT">^1</xliff:g> zdjęcia…</item>
+ <item quantity="many">Usuwam <xliff:g id="COUNT">^1</xliff:g> zdjęć…</item>
+ <item quantity="other">Usuwam <xliff:g id="COUNT">^1</xliff:g> zdjęcia…</item>
+ <item quantity="one">Usuwam zdjęcie…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="few">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na usunięcie <xliff:g id="COUNT">^2</xliff:g> elementów?</item>
<item quantity="many">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na usunięcie <xliff:g id="COUNT">^2</xliff:g> elementów?</item>
<item quantity="other">Zezwolić aplikacji <xliff:g id="APP_NAME_1">^1</xliff:g> na usunięcie <xliff:g id="COUNT">^2</xliff:g> elementu?</item>
<item quantity="one">Zezwolić aplikacji <xliff:g id="APP_NAME_0">^1</xliff:g> na usunięcie tego elementu?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="few">Usuwam <xliff:g id="COUNT">^1</xliff:g> elementy…</item>
+ <item quantity="many">Usuwam <xliff:g id="COUNT">^1</xliff:g> elementów…</item>
+ <item quantity="other">Usuwam <xliff:g id="COUNT">^1</xliff:g> elementu…</item>
+ <item quantity="one">Usuwam element…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"Aplikacja <xliff:g id="APP_NAME">%s</xliff:g> nie może przetworzyć plików multimediów"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Anulowano przetwarzanie multimediów"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Błąd przetwarzania multimediów"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Przetworzono multimedia"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Rozpoczęto przetwarzanie multimediów"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Przetwarzam multimedia…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Anuluj"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Czekaj"</string>
</resources>
diff --git a/res/values-pt-rBR/strings.xml b/res/values-pt-rBR/strings.xml
index d0ff6d6..82f8b43 100644
--- a/res/values-pt-rBR/strings.xml
+++ b/res/values-pt-rBR/strings.xml
@@ -47,64 +47,136 @@
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> arquivo de áudio?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> arquivos de áudio?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="one">Modificando <xliff:g id="COUNT">^1</xliff:g> arquivo de áudio…</item>
+ <item quantity="other">Modificando <xliff:g id="COUNT">^1</xliff:g> arquivos de áudio…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> vídeo?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> vídeos?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="one">Modificando <xliff:g id="COUNT">^1</xliff:g> vídeo…</item>
+ <item quantity="other">Modificando <xliff:g id="COUNT">^1</xliff:g> vídeos…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> foto?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> fotos?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="one">Modificando <xliff:g id="COUNT">^1</xliff:g> foto…</item>
+ <item quantity="other">Modificando <xliff:g id="COUNT">^1</xliff:g> fotos…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> item?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> itens?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="one">Modificando <xliff:g id="COUNT">^1</xliff:g> item…</item>
+ <item quantity="other">Modificando <xliff:g id="COUNT">^1</xliff:g> itens…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> mova <xliff:g id="COUNT">^2</xliff:g> arquivo de áudio para a lixeira?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> mova <xliff:g id="COUNT">^2</xliff:g> arquivos de áudio para a lixeira?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="one">Movendo <xliff:g id="COUNT">^1</xliff:g> arquivo de áudio para a lixeira…</item>
+ <item quantity="other">Movendo <xliff:g id="COUNT">^1</xliff:g> arquivos de áudio para a lixeira…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> mova <xliff:g id="COUNT">^2</xliff:g> vídeo para a lixeira?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> mova <xliff:g id="COUNT">^2</xliff:g> vídeos para a lixeira?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="one">Movendo <xliff:g id="COUNT">^1</xliff:g> vídeo para a lixeira…</item>
+ <item quantity="other">Movendo <xliff:g id="COUNT">^1</xliff:g> vídeos para a lixeira…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> mova <xliff:g id="COUNT">^2</xliff:g> foto para a lixeira?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> mova <xliff:g id="COUNT">^2</xliff:g> fotos para a lixeira?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="one">Movendo <xliff:g id="COUNT">^1</xliff:g> foto para a lixeira…</item>
+ <item quantity="other">Movendo <xliff:g id="COUNT">^1</xliff:g> fotos para a lixeira…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> mova <xliff:g id="COUNT">^2</xliff:g> item para a lixeira?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> mova <xliff:g id="COUNT">^2</xliff:g> itens para a lixeira?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="one">Movendo <xliff:g id="COUNT">^1</xliff:g> item para a lixeira…</item>
+ <item quantity="other">Movendo <xliff:g id="COUNT">^1</xliff:g> itens para a lixeira…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> retire <xliff:g id="COUNT">^2</xliff:g> arquivo de áudio da lixeira?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> retire <xliff:g id="COUNT">^2</xliff:g> arquivos de áudio da lixeira?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="one">Retirando <xliff:g id="COUNT">^1</xliff:g> arquivo de áudio da lixeira…</item>
+ <item quantity="other">Retirando <xliff:g id="COUNT">^1</xliff:g> arquivos de áudio da lixeira…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> retire <xliff:g id="COUNT">^2</xliff:g> vídeo da lixeira?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> retire <xliff:g id="COUNT">^2</xliff:g> vídeos da lixeira?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="one">Retirando <xliff:g id="COUNT">^1</xliff:g> vídeo da lixeira…</item>
+ <item quantity="other">Retirando <xliff:g id="COUNT">^1</xliff:g> vídeos da lixeira…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> retire <xliff:g id="COUNT">^2</xliff:g> foto da lixeira?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> retire <xliff:g id="COUNT">^2</xliff:g> fotos da lixeira?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="one">Retirando <xliff:g id="COUNT">^1</xliff:g> foto da lixeira…</item>
+ <item quantity="other">Retirando <xliff:g id="COUNT">^1</xliff:g> fotos da lixeira…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> retire <xliff:g id="COUNT">^2</xliff:g> item da lixeira?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> retire <xliff:g id="COUNT">^2</xliff:g> itens da lixeira?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="one">Retirando <xliff:g id="COUNT">^1</xliff:g> item da lixeira…</item>
+ <item quantity="other">Retirando <xliff:g id="COUNT">^1</xliff:g> itens da lixeira…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> exclua <xliff:g id="COUNT">^2</xliff:g> arquivo de áudio?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> exclua <xliff:g id="COUNT">^2</xliff:g> arquivos de áudio?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="one">Excluindo <xliff:g id="COUNT">^1</xliff:g> arquivo de áudio…</item>
+ <item quantity="other">Excluindo <xliff:g id="COUNT">^1</xliff:g> arquivos de áudio…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> exclua <xliff:g id="COUNT">^2</xliff:g> vídeo?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> exclua <xliff:g id="COUNT">^2</xliff:g> vídeos?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="one">Excluindo <xliff:g id="COUNT">^1</xliff:g> vídeo…</item>
+ <item quantity="other">Excluindo <xliff:g id="COUNT">^1</xliff:g> vídeos…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> exclua <xliff:g id="COUNT">^2</xliff:g> foto?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> exclua <xliff:g id="COUNT">^2</xliff:g> fotos?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="one">Excluindo <xliff:g id="COUNT">^1</xliff:g> foto…</item>
+ <item quantity="other">Excluindo <xliff:g id="COUNT">^1</xliff:g> fotos…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> exclua <xliff:g id="COUNT">^2</xliff:g> item?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> exclua <xliff:g id="COUNT">^2</xliff:g> itens?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="one">Excluindo <xliff:g id="COUNT">^1</xliff:g> item…</item>
+ <item quantity="other">Excluindo <xliff:g id="COUNT">^1</xliff:g> itens…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"Não é possível processar arquivos de mídia no app <xliff:g id="APP_NAME">%s</xliff:g>"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Processamento de mídia cancelado"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Erro no processamento de mídia"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Processamento de mídia concluído"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Processamento de mídia iniciado"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Processando mídia…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Cancelar"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Aguardar"</string>
</resources>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 27c1cb0..058b69b 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">Permitir que a app <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> ficheiros de áudio?</item>
<item quantity="one">Permitir que a app <xliff:g id="APP_NAME_0">^1</xliff:g> modifique este ficheiro de áudio?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other">A modificar <xliff:g id="COUNT">^1</xliff:g> ficheiros de áudio…</item>
+ <item quantity="one">A modificar o ficheiro de áudio…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">Permitir que a app <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> vídeos?</item>
<item quantity="one">Permitir que a app <xliff:g id="APP_NAME_0">^1</xliff:g> modifique este vídeo?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other">A modificar <xliff:g id="COUNT">^1</xliff:g> vídeos…</item>
+ <item quantity="one">A modificar o vídeo…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">Permitir que a app <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> fotos?</item>
<item quantity="one">Permitir que a app <xliff:g id="APP_NAME_0">^1</xliff:g> modifique esta foto?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other">A modificar <xliff:g id="COUNT">^1</xliff:g> fotos…</item>
+ <item quantity="one">A modificar a foto…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">Permitir que a app <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> itens?</item>
<item quantity="one">Permitir que a app <xliff:g id="APP_NAME_0">^1</xliff:g> modifique este item?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other">A modificar <xliff:g id="COUNT">^1</xliff:g> itens…</item>
+ <item quantity="one">A modificar o item…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">Permitir que a app <xliff:g id="APP_NAME_1">^1</xliff:g> mova <xliff:g id="COUNT">^2</xliff:g> ficheiros de áudio para o lixo?</item>
<item quantity="one">Permitir que a app <xliff:g id="APP_NAME_0">^1</xliff:g> mova este ficheiro de áudio para o lixo?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other">A mover <xliff:g id="COUNT">^1</xliff:g> ficheiros de áudio para o lixo…</item>
+ <item quantity="one">A mover o ficheiro de áudio para o lixo…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">Permitir que a app <xliff:g id="APP_NAME_1">^1</xliff:g> mova <xliff:g id="COUNT">^2</xliff:g> vídeos para o lixo?</item>
<item quantity="one">Permitir que a app <xliff:g id="APP_NAME_0">^1</xliff:g> mova este vídeo para o lixo?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other">A mover <xliff:g id="COUNT">^1</xliff:g> vídeos para o lixo…</item>
+ <item quantity="one">A mover o vídeo para o lixo…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">Permitir que a app <xliff:g id="APP_NAME_1">^1</xliff:g> mova <xliff:g id="COUNT">^2</xliff:g> fotos para o lixo?</item>
<item quantity="one">Permitir que a app <xliff:g id="APP_NAME_0">^1</xliff:g> mova esta foto para o lixo?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other">A mover <xliff:g id="COUNT">^1</xliff:g> fotos para o lixo…</item>
+ <item quantity="one">A mover a foto para o lixo…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">Permitir que a app <xliff:g id="APP_NAME_1">^1</xliff:g> mova <xliff:g id="COUNT">^2</xliff:g> itens para o lixo?</item>
<item quantity="one">Permitir que a app <xliff:g id="APP_NAME_0">^1</xliff:g> mova este item para o lixo?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other">A mover <xliff:g id="COUNT">^1</xliff:g> itens para o lixo…</item>
+ <item quantity="one">A mover o item para o lixo…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">Permitir que a app <xliff:g id="APP_NAME_1">^1</xliff:g> retire <xliff:g id="COUNT">^2</xliff:g> ficheiros de áudio do lixo?</item>
<item quantity="one">Permitir que a app <xliff:g id="APP_NAME_0">^1</xliff:g> retire este ficheiro de áudio do lixo?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other">A retirar <xliff:g id="COUNT">^1</xliff:g> ficheiros de áudio do lixo…</item>
+ <item quantity="one">A retirar o ficheiro de áudio do lixo…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">Permitir que a app <xliff:g id="APP_NAME_1">^1</xliff:g> retire <xliff:g id="COUNT">^2</xliff:g> vídeos do lixo?</item>
<item quantity="one">Permitir que a app <xliff:g id="APP_NAME_0">^1</xliff:g> retire este vídeo do lixo?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other">A retirar <xliff:g id="COUNT">^1</xliff:g> vídeos do lixo…</item>
+ <item quantity="one">A retirar o vídeo do lixo…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">Permitir que a app <xliff:g id="APP_NAME_1">^1</xliff:g> retire <xliff:g id="COUNT">^2</xliff:g> fotos do lixo?</item>
<item quantity="one">Permitir que a app <xliff:g id="APP_NAME_0">^1</xliff:g> retire esta foto do lixo?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other">A retirar <xliff:g id="COUNT">^1</xliff:g> fotos do lixo…</item>
+ <item quantity="one">A retirar a foto do lixo…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">Permitir que a app <xliff:g id="APP_NAME_1">^1</xliff:g> retire <xliff:g id="COUNT">^2</xliff:g> itens do lixo?</item>
<item quantity="one">Permitir que a app <xliff:g id="APP_NAME_0">^1</xliff:g> retire este item do lixo?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other">A retirar <xliff:g id="COUNT">^1</xliff:g> itens do lixo…</item>
+ <item quantity="one">A retirar o item do lixo…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">Permitir que a app <xliff:g id="APP_NAME_1">^1</xliff:g> elimine <xliff:g id="COUNT">^2</xliff:g> ficheiros de áudio?</item>
<item quantity="one">Permitir que a app <xliff:g id="APP_NAME_0">^1</xliff:g> elimine este ficheiro de áudio?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other">A eliminar <xliff:g id="COUNT">^1</xliff:g> ficheiros de áudio…</item>
+ <item quantity="one">A eliminar o ficheiro de áudio…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">Permitir que a app <xliff:g id="APP_NAME_1">^1</xliff:g> elimine <xliff:g id="COUNT">^2</xliff:g> vídeos?</item>
<item quantity="one">Permitir que a app <xliff:g id="APP_NAME_0">^1</xliff:g> elimine este vídeo?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other">A eliminar <xliff:g id="COUNT">^1</xliff:g> vídeos…</item>
+ <item quantity="one">A eliminar o vídeo…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">Permitir que a app <xliff:g id="APP_NAME_1">^1</xliff:g> elimine <xliff:g id="COUNT">^2</xliff:g> fotos?</item>
<item quantity="one">Permitir que a app <xliff:g id="APP_NAME_0">^1</xliff:g> elimine esta foto?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other">A eliminar <xliff:g id="COUNT">^1</xliff:g> fotos…</item>
+ <item quantity="one">A eliminar a foto…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">Permitir que a app <xliff:g id="APP_NAME_1">^1</xliff:g> elimine <xliff:g id="COUNT">^2</xliff:g> itens?</item>
<item quantity="one">Permitir que a app <xliff:g id="APP_NAME_0">^1</xliff:g> elimine este item?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other">A eliminar <xliff:g id="COUNT">^1</xliff:g> itens…</item>
+ <item quantity="one">A eliminar o item…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"A app <xliff:g id="APP_NAME">%s</xliff:g> não pode processar ficheiros multimédia"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Processamento de multimédia cancelado"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Erro de processamento de multimédia"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Êxito do processamento de multimédia"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Processamento de multimédia iniciado"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"A processar multimédia…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Cancelar"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Aguardar"</string>
</resources>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index d0ff6d6..82f8b43 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -47,64 +47,136 @@
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> arquivo de áudio?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> arquivos de áudio?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="one">Modificando <xliff:g id="COUNT">^1</xliff:g> arquivo de áudio…</item>
+ <item quantity="other">Modificando <xliff:g id="COUNT">^1</xliff:g> arquivos de áudio…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> vídeo?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> vídeos?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="one">Modificando <xliff:g id="COUNT">^1</xliff:g> vídeo…</item>
+ <item quantity="other">Modificando <xliff:g id="COUNT">^1</xliff:g> vídeos…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> foto?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> fotos?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="one">Modificando <xliff:g id="COUNT">^1</xliff:g> foto…</item>
+ <item quantity="other">Modificando <xliff:g id="COUNT">^1</xliff:g> fotos…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> item?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> modifique <xliff:g id="COUNT">^2</xliff:g> itens?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="one">Modificando <xliff:g id="COUNT">^1</xliff:g> item…</item>
+ <item quantity="other">Modificando <xliff:g id="COUNT">^1</xliff:g> itens…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> mova <xliff:g id="COUNT">^2</xliff:g> arquivo de áudio para a lixeira?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> mova <xliff:g id="COUNT">^2</xliff:g> arquivos de áudio para a lixeira?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="one">Movendo <xliff:g id="COUNT">^1</xliff:g> arquivo de áudio para a lixeira…</item>
+ <item quantity="other">Movendo <xliff:g id="COUNT">^1</xliff:g> arquivos de áudio para a lixeira…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> mova <xliff:g id="COUNT">^2</xliff:g> vídeo para a lixeira?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> mova <xliff:g id="COUNT">^2</xliff:g> vídeos para a lixeira?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="one">Movendo <xliff:g id="COUNT">^1</xliff:g> vídeo para a lixeira…</item>
+ <item quantity="other">Movendo <xliff:g id="COUNT">^1</xliff:g> vídeos para a lixeira…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> mova <xliff:g id="COUNT">^2</xliff:g> foto para a lixeira?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> mova <xliff:g id="COUNT">^2</xliff:g> fotos para a lixeira?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="one">Movendo <xliff:g id="COUNT">^1</xliff:g> foto para a lixeira…</item>
+ <item quantity="other">Movendo <xliff:g id="COUNT">^1</xliff:g> fotos para a lixeira…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> mova <xliff:g id="COUNT">^2</xliff:g> item para a lixeira?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> mova <xliff:g id="COUNT">^2</xliff:g> itens para a lixeira?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="one">Movendo <xliff:g id="COUNT">^1</xliff:g> item para a lixeira…</item>
+ <item quantity="other">Movendo <xliff:g id="COUNT">^1</xliff:g> itens para a lixeira…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> retire <xliff:g id="COUNT">^2</xliff:g> arquivo de áudio da lixeira?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> retire <xliff:g id="COUNT">^2</xliff:g> arquivos de áudio da lixeira?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="one">Retirando <xliff:g id="COUNT">^1</xliff:g> arquivo de áudio da lixeira…</item>
+ <item quantity="other">Retirando <xliff:g id="COUNT">^1</xliff:g> arquivos de áudio da lixeira…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> retire <xliff:g id="COUNT">^2</xliff:g> vídeo da lixeira?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> retire <xliff:g id="COUNT">^2</xliff:g> vídeos da lixeira?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="one">Retirando <xliff:g id="COUNT">^1</xliff:g> vídeo da lixeira…</item>
+ <item quantity="other">Retirando <xliff:g id="COUNT">^1</xliff:g> vídeos da lixeira…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> retire <xliff:g id="COUNT">^2</xliff:g> foto da lixeira?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> retire <xliff:g id="COUNT">^2</xliff:g> fotos da lixeira?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="one">Retirando <xliff:g id="COUNT">^1</xliff:g> foto da lixeira…</item>
+ <item quantity="other">Retirando <xliff:g id="COUNT">^1</xliff:g> fotos da lixeira…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> retire <xliff:g id="COUNT">^2</xliff:g> item da lixeira?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> retire <xliff:g id="COUNT">^2</xliff:g> itens da lixeira?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="one">Retirando <xliff:g id="COUNT">^1</xliff:g> item da lixeira…</item>
+ <item quantity="other">Retirando <xliff:g id="COUNT">^1</xliff:g> itens da lixeira…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> exclua <xliff:g id="COUNT">^2</xliff:g> arquivo de áudio?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> exclua <xliff:g id="COUNT">^2</xliff:g> arquivos de áudio?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="one">Excluindo <xliff:g id="COUNT">^1</xliff:g> arquivo de áudio…</item>
+ <item quantity="other">Excluindo <xliff:g id="COUNT">^1</xliff:g> arquivos de áudio…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> exclua <xliff:g id="COUNT">^2</xliff:g> vídeo?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> exclua <xliff:g id="COUNT">^2</xliff:g> vídeos?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="one">Excluindo <xliff:g id="COUNT">^1</xliff:g> vídeo…</item>
+ <item quantity="other">Excluindo <xliff:g id="COUNT">^1</xliff:g> vídeos…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> exclua <xliff:g id="COUNT">^2</xliff:g> foto?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> exclua <xliff:g id="COUNT">^2</xliff:g> fotos?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="one">Excluindo <xliff:g id="COUNT">^1</xliff:g> foto…</item>
+ <item quantity="other">Excluindo <xliff:g id="COUNT">^1</xliff:g> fotos…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="one">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> exclua <xliff:g id="COUNT">^2</xliff:g> item?</item>
<item quantity="other">Permitir que o app <xliff:g id="APP_NAME_1">^1</xliff:g> exclua <xliff:g id="COUNT">^2</xliff:g> itens?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="one">Excluindo <xliff:g id="COUNT">^1</xliff:g> item…</item>
+ <item quantity="other">Excluindo <xliff:g id="COUNT">^1</xliff:g> itens…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"Não é possível processar arquivos de mídia no app <xliff:g id="APP_NAME">%s</xliff:g>"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Processamento de mídia cancelado"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Erro no processamento de mídia"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Processamento de mídia concluído"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Processamento de mídia iniciado"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Processando mídia…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Cancelar"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Aguardar"</string>
</resources>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 8df20b8..4bd0b43 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -50,79 +50,167 @@
<item quantity="other">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să modifice <xliff:g id="COUNT">^2</xliff:g> de fișiere audio?</item>
<item quantity="one">Permiteți ca <xliff:g id="APP_NAME_0">^1</xliff:g> să modifice acest fișier audio?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="few">Se modifică <xliff:g id="COUNT">^1</xliff:g> fișiere audio…</item>
+ <item quantity="other">Se modifică <xliff:g id="COUNT">^1</xliff:g> de fișiere audio…</item>
+ <item quantity="one">Se modifică fișierul audio…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="few">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să modifice <xliff:g id="COUNT">^2</xliff:g> videoclipuri?</item>
<item quantity="other">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să modifice <xliff:g id="COUNT">^2</xliff:g> de videoclipuri?</item>
<item quantity="one">Permiteți ca <xliff:g id="APP_NAME_0">^1</xliff:g> să modifice acest videoclip?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="few">Se modifică <xliff:g id="COUNT">^1</xliff:g> videoclipuri…</item>
+ <item quantity="other">Se modifică <xliff:g id="COUNT">^1</xliff:g> de videoclipuri…</item>
+ <item quantity="one">Se modifică videoclipul…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="few">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să modifice <xliff:g id="COUNT">^2</xliff:g> fotografii?</item>
<item quantity="other">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să modifice <xliff:g id="COUNT">^2</xliff:g> de fotografii?</item>
<item quantity="one">Permiteți ca <xliff:g id="APP_NAME_0">^1</xliff:g> să modifice această fotografie?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="few">Se modifică <xliff:g id="COUNT">^1</xliff:g> fotografii…</item>
+ <item quantity="other">Se modifică <xliff:g id="COUNT">^1</xliff:g> de fotografii…</item>
+ <item quantity="one">Se modifică fotografia…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="few">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să modifice <xliff:g id="COUNT">^2</xliff:g> elemente?</item>
<item quantity="other">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să modifice <xliff:g id="COUNT">^2</xliff:g> de elemente?</item>
<item quantity="one">Permiteți ca <xliff:g id="APP_NAME_0">^1</xliff:g> să modifice acest element?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="few">Se modifică <xliff:g id="COUNT">^1</xliff:g> elemente…</item>
+ <item quantity="other">Se modifică <xliff:g id="COUNT">^1</xliff:g> de elemente…</item>
+ <item quantity="one">Se modifică un element…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="few">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să mute <xliff:g id="COUNT">^2</xliff:g> fișiere audio în coșul de gunoi?</item>
<item quantity="other">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să mute <xliff:g id="COUNT">^2</xliff:g> de fișiere audio în coșul de gunoi?</item>
<item quantity="one">Permiteți ca <xliff:g id="APP_NAME_0">^1</xliff:g> să mute acest fișier audio în coșul de gunoi?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="few">Se mută <xliff:g id="COUNT">^1</xliff:g> fișiere audio în coșul de gunoi…</item>
+ <item quantity="other">Se mută <xliff:g id="COUNT">^1</xliff:g> de fișiere audio în coșul de gunoi…</item>
+ <item quantity="one">Se mută fișierul audio în coșul de gunoi…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="few">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să mute <xliff:g id="COUNT">^2</xliff:g> videoclipuri în coșul de gunoi?</item>
<item quantity="other">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să mute <xliff:g id="COUNT">^2</xliff:g> de videoclipuri în coșul de gunoi?</item>
<item quantity="one">Permiteți ca <xliff:g id="APP_NAME_0">^1</xliff:g> să mute acest videoclip în coșul de gunoi?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="few">Se mută <xliff:g id="COUNT">^1</xliff:g> videoclipuri în coșul de gunoi…</item>
+ <item quantity="other">Se mută <xliff:g id="COUNT">^1</xliff:g> de videoclipuri în coșul de gunoi…</item>
+ <item quantity="one">Se mută videoclipul în coșul de gunoi…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="few">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să mute <xliff:g id="COUNT">^2</xliff:g> fotografii în coșul de gunoi?</item>
<item quantity="other">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să mute <xliff:g id="COUNT">^2</xliff:g> de fotografii în coșul de gunoi?</item>
<item quantity="one">Permiteți ca <xliff:g id="APP_NAME_0">^1</xliff:g> să mute această fotografie în coșul de gunoi?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="few">Se mută <xliff:g id="COUNT">^1</xliff:g> fotografii în coșul de gunoi…</item>
+ <item quantity="other">Se mută <xliff:g id="COUNT">^1</xliff:g> de fotografii în coșul de gunoi…</item>
+ <item quantity="one">Se mută fotografia în coșul de gunoi…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="few">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să mute <xliff:g id="COUNT">^2</xliff:g> elemente în coșul de gunoi?</item>
<item quantity="other">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să mute <xliff:g id="COUNT">^2</xliff:g> de elemente în coșul de gunoi?</item>
<item quantity="one">Permiteți ca <xliff:g id="APP_NAME_0">^1</xliff:g> să mute acest element în coșul de gunoi?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="few">Se mută <xliff:g id="COUNT">^1</xliff:g> elemente în coșul de gunoi…</item>
+ <item quantity="other">Se mută <xliff:g id="COUNT">^1</xliff:g> de elemente în coșul de gunoi…</item>
+ <item quantity="one">Se mută elementul în coșul de gunoi…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="few">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să scoată <xliff:g id="COUNT">^2</xliff:g> fișiere audio din coșul de gunoi?</item>
<item quantity="other">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să scoată <xliff:g id="COUNT">^2</xliff:g> de fișiere audio din coșul de gunoi?</item>
<item quantity="one">Permiteți ca <xliff:g id="APP_NAME_0">^1</xliff:g> să scoată acest fișier audio din coșul de gunoi?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="few">Se scot <xliff:g id="COUNT">^1</xliff:g> fișiere audio din coșul de gunoi…</item>
+ <item quantity="other">Se scot <xliff:g id="COUNT">^1</xliff:g> de fișiere audio din coșul de gunoi…</item>
+ <item quantity="one">Se scoate fișierul audio din coșul de gunoi…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="few">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să scoată <xliff:g id="COUNT">^2</xliff:g> videoclipuri din coșul de gunoi?</item>
<item quantity="other">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să scoată <xliff:g id="COUNT">^2</xliff:g> de videoclipuri din coșul de gunoi?</item>
<item quantity="one">Permiteți ca <xliff:g id="APP_NAME_0">^1</xliff:g> să scoată acest videoclip din coșul de gunoi?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="few">Se scot <xliff:g id="COUNT">^1</xliff:g> videoclipuri din coșul de gunoi…</item>
+ <item quantity="other">Se scot <xliff:g id="COUNT">^1</xliff:g> de videoclipuri din coșul de gunoi…</item>
+ <item quantity="one">Se scoate videoclipul din coșul de gunoi…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="few">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să scoată <xliff:g id="COUNT">^2</xliff:g> fotografii din coșul de gunoi?</item>
<item quantity="other">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să scoată <xliff:g id="COUNT">^2</xliff:g> de fotografii din coșul de gunoi?</item>
<item quantity="one">Permiteți ca <xliff:g id="APP_NAME_0">^1</xliff:g> să scoată această fotografie din coșul de gunoi?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="few">Se scot <xliff:g id="COUNT">^1</xliff:g> fotografii din coșul de gunoi…</item>
+ <item quantity="other">Se scot <xliff:g id="COUNT">^1</xliff:g> de fotografii din coșul de gunoi…</item>
+ <item quantity="one">Se scoate fotografia din coșul de gunoi…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="few">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să scoată <xliff:g id="COUNT">^2</xliff:g> elemente din coșul de gunoi?</item>
<item quantity="other">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să scoată <xliff:g id="COUNT">^2</xliff:g> de elemente din coșul de gunoi?</item>
<item quantity="one">Permiteți ca <xliff:g id="APP_NAME_0">^1</xliff:g> să scoată acest element din coșul de gunoi?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="few">Se scot <xliff:g id="COUNT">^1</xliff:g> elemente din coșul de gunoi…</item>
+ <item quantity="other">Se scot <xliff:g id="COUNT">^1</xliff:g> de elemente din coșul de gunoi…</item>
+ <item quantity="one">Se scoate elementul din coșul de gunoi…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="few">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să șteargă <xliff:g id="COUNT">^2</xliff:g> fișiere audio?</item>
<item quantity="other">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să șteargă <xliff:g id="COUNT">^2</xliff:g> de fișiere audio?</item>
<item quantity="one">Permiteți ca <xliff:g id="APP_NAME_0">^1</xliff:g> să șteargă acest fișier audio?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="few">Se șterg <xliff:g id="COUNT">^1</xliff:g> fișiere audio…</item>
+ <item quantity="other">Se șterg <xliff:g id="COUNT">^1</xliff:g> de fișiere audio…</item>
+ <item quantity="one">Se șterge fișierul audio…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="few">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să șteargă <xliff:g id="COUNT">^2</xliff:g> videoclipuri?</item>
<item quantity="other">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să șteargă <xliff:g id="COUNT">^2</xliff:g> de videoclipuri?</item>
<item quantity="one">Permiteți ca <xliff:g id="APP_NAME_0">^1</xliff:g> să șteargă acest videoclip?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="few">Se șterg <xliff:g id="COUNT">^1</xliff:g> videoclipuri…</item>
+ <item quantity="other">Se șterg <xliff:g id="COUNT">^1</xliff:g> de videoclipuri…</item>
+ <item quantity="one">Se șterge videoclipul…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="few">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să șteargă <xliff:g id="COUNT">^2</xliff:g> fotografii?</item>
<item quantity="other">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să șteargă <xliff:g id="COUNT">^2</xliff:g> de fotografii?</item>
<item quantity="one">Permiteți ca <xliff:g id="APP_NAME_0">^1</xliff:g> să șteargă această fotografie?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="few">Se șterg <xliff:g id="COUNT">^1</xliff:g> fotografii…</item>
+ <item quantity="other">Se șterg <xliff:g id="COUNT">^1</xliff:g> de fotografii…</item>
+ <item quantity="one">Se șterge fotografia…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="few">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să șteargă <xliff:g id="COUNT">^2</xliff:g> elemente?</item>
<item quantity="other">Permiteți ca <xliff:g id="APP_NAME_1">^1</xliff:g> să șteargă <xliff:g id="COUNT">^2</xliff:g> de elemente?</item>
<item quantity="one">Permiteți ca <xliff:g id="APP_NAME_0">^1</xliff:g> să șteargă acest element?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="few">Se șterg <xliff:g id="COUNT">^1</xliff:g> elemente…</item>
+ <item quantity="other">Se șterg <xliff:g id="COUNT">^1</xliff:g> de elemente…</item>
+ <item quantity="one">Se șterge elementul…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> nu poate procesa fișiere media"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Procesarea conținutului media a fost anulată"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Eroare la procesarea conținutului media"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Procesarea conținutului media s-a finalizat"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Procesarea conținutului media a început"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Se procesează conținutul media…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Anulați"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Așteptați"</string>
</resources>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index d7a1aaa..054d9fc 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -53,94 +53,198 @@
<item quantity="many">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" изменить <xliff:g id="COUNT">^2</xliff:g> аудиофайлов?</item>
<item quantity="other">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" изменить <xliff:g id="COUNT">^2</xliff:g> аудиофайла?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="one">Изменение <xliff:g id="COUNT">^1</xliff:g> аудиофайла…</item>
+ <item quantity="few">Изменение <xliff:g id="COUNT">^1</xliff:g> аудиофайлов…</item>
+ <item quantity="many">Изменение <xliff:g id="COUNT">^1</xliff:g> аудиофайлов…</item>
+ <item quantity="other">Изменение <xliff:g id="COUNT">^1</xliff:g> аудиофайла…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="one">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" изменить <xliff:g id="COUNT">^2</xliff:g> видео?</item>
<item quantity="few">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" изменить <xliff:g id="COUNT">^2</xliff:g> видео?</item>
<item quantity="many">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" изменить <xliff:g id="COUNT">^2</xliff:g> видео?</item>
<item quantity="other">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" изменить <xliff:g id="COUNT">^2</xliff:g> видео?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="one">Изменение <xliff:g id="COUNT">^1</xliff:g> видео…</item>
+ <item quantity="few">Изменение <xliff:g id="COUNT">^1</xliff:g> видео…</item>
+ <item quantity="many">Изменение <xliff:g id="COUNT">^1</xliff:g> видео…</item>
+ <item quantity="other">Изменение <xliff:g id="COUNT">^1</xliff:g> видео…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="one">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" изменить <xliff:g id="COUNT">^2</xliff:g> фото?</item>
<item quantity="few">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" изменить <xliff:g id="COUNT">^2</xliff:g> фото?</item>
<item quantity="many">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" изменить <xliff:g id="COUNT">^2</xliff:g> фото?</item>
<item quantity="other">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" изменить <xliff:g id="COUNT">^2</xliff:g> фото?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="one">Изменение <xliff:g id="COUNT">^1</xliff:g> фотографии…</item>
+ <item quantity="few">Изменение <xliff:g id="COUNT">^1</xliff:g> фотографий…</item>
+ <item quantity="many">Изменение <xliff:g id="COUNT">^1</xliff:g> фотографий…</item>
+ <item quantity="other">Изменение <xliff:g id="COUNT">^1</xliff:g> фотографии…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="one">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" изменить <xliff:g id="COUNT">^2</xliff:g> объект?</item>
<item quantity="few">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" изменить <xliff:g id="COUNT">^2</xliff:g> объекта?</item>
<item quantity="many">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" изменить <xliff:g id="COUNT">^2</xliff:g> объектов?</item>
<item quantity="other">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" изменить <xliff:g id="COUNT">^2</xliff:g> объекта?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="one">Изменение <xliff:g id="COUNT">^1</xliff:g> объекта…</item>
+ <item quantity="few">Изменение <xliff:g id="COUNT">^1</xliff:g> объектов…</item>
+ <item quantity="many">Изменение <xliff:g id="COUNT">^1</xliff:g> объектов…</item>
+ <item quantity="other">Изменение <xliff:g id="COUNT">^1</xliff:g> объекта…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="one">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" переместить <xliff:g id="COUNT">^2</xliff:g> аудиофайл в корзину?</item>
<item quantity="few">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" переместить <xliff:g id="COUNT">^2</xliff:g> аудиофайла в корзину?</item>
<item quantity="many">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" переместить <xliff:g id="COUNT">^2</xliff:g> аудиофайлов в корзину?</item>
<item quantity="other">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" переместить <xliff:g id="COUNT">^2</xliff:g> аудиофайла в корзину?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="one">Перемещение <xliff:g id="COUNT">^1</xliff:g> аудиофайла в корзину…</item>
+ <item quantity="few">Перемещение <xliff:g id="COUNT">^1</xliff:g> аудиофайлов в корзину…</item>
+ <item quantity="many">Перемещение <xliff:g id="COUNT">^1</xliff:g> аудиофайлов в корзину…</item>
+ <item quantity="other">Перемещение <xliff:g id="COUNT">^1</xliff:g> аудиофайла в корзину…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="one">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" переместить <xliff:g id="COUNT">^2</xliff:g> видео в корзину?</item>
<item quantity="few">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" переместить <xliff:g id="COUNT">^2</xliff:g> видео в корзину?</item>
<item quantity="many">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" переместить <xliff:g id="COUNT">^2</xliff:g> видео в корзину?</item>
<item quantity="other">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" переместить <xliff:g id="COUNT">^2</xliff:g> видео в корзину?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="one">Перемещение <xliff:g id="COUNT">^1</xliff:g> видео в корзину…</item>
+ <item quantity="few">Перемещение <xliff:g id="COUNT">^1</xliff:g> видео в корзину…</item>
+ <item quantity="many">Перемещение <xliff:g id="COUNT">^1</xliff:g> видео в корзину…</item>
+ <item quantity="other">Перемещение <xliff:g id="COUNT">^1</xliff:g> видео в корзину…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="one">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" переместить <xliff:g id="COUNT">^2</xliff:g> фото в корзину?</item>
<item quantity="few">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" переместить <xliff:g id="COUNT">^2</xliff:g> фото в корзину?</item>
<item quantity="many">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" переместить <xliff:g id="COUNT">^2</xliff:g> фото в корзину?</item>
<item quantity="other">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" переместить <xliff:g id="COUNT">^2</xliff:g> фото в корзину?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="one">Перемещение <xliff:g id="COUNT">^1</xliff:g> фотографии в корзину…</item>
+ <item quantity="few">Перемещение <xliff:g id="COUNT">^1</xliff:g> фотографий в корзину…</item>
+ <item quantity="many">Перемещение <xliff:g id="COUNT">^1</xliff:g> фотографий в корзину…</item>
+ <item quantity="other">Перемещение <xliff:g id="COUNT">^1</xliff:g> фотографии в корзину…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="one">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" переместить <xliff:g id="COUNT">^2</xliff:g> объект в корзину?</item>
<item quantity="few">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" переместить <xliff:g id="COUNT">^2</xliff:g> объекта в корзину?</item>
<item quantity="many">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" переместить <xliff:g id="COUNT">^2</xliff:g> объектов в корзину?</item>
<item quantity="other">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" переместить <xliff:g id="COUNT">^2</xliff:g> объекта в корзину?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="one">Перемещение <xliff:g id="COUNT">^1</xliff:g> объекта в корзину…</item>
+ <item quantity="few">Перемещение <xliff:g id="COUNT">^1</xliff:g> объектов в корзину…</item>
+ <item quantity="many">Перемещение <xliff:g id="COUNT">^1</xliff:g> объектов в корзину…</item>
+ <item quantity="other">Перемещение <xliff:g id="COUNT">^1</xliff:g> объекта в корзину…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="one">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" восстановить <xliff:g id="COUNT">^2</xliff:g> аудиофайл из корзины?</item>
<item quantity="few">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" восстановить <xliff:g id="COUNT">^2</xliff:g> аудиофайла из корзины?</item>
<item quantity="many">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" восстановить <xliff:g id="COUNT">^2</xliff:g> аудиофайлов из корзины?</item>
<item quantity="other">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" восстановить <xliff:g id="COUNT">^2</xliff:g> аудиофайла из корзины?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="one">Восстановление <xliff:g id="COUNT">^1</xliff:g> аудиофайла из корзины…</item>
+ <item quantity="few">Восстановление <xliff:g id="COUNT">^1</xliff:g> аудиофайлов из корзины…</item>
+ <item quantity="many">Восстановление <xliff:g id="COUNT">^1</xliff:g> аудиофайлов из корзины…</item>
+ <item quantity="other">Восстановление <xliff:g id="COUNT">^1</xliff:g> аудиофайла из корзины…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="one">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" восстановить <xliff:g id="COUNT">^2</xliff:g> видео из корзины?</item>
<item quantity="few">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" восстановить <xliff:g id="COUNT">^2</xliff:g> видео из корзины?</item>
<item quantity="many">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" восстановить <xliff:g id="COUNT">^2</xliff:g> видео из корзины?</item>
<item quantity="other">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" восстановить <xliff:g id="COUNT">^2</xliff:g> видео из корзины?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="one">Восстановление <xliff:g id="COUNT">^1</xliff:g> видео из корзины…</item>
+ <item quantity="few">Восстановление <xliff:g id="COUNT">^1</xliff:g> видео из корзины…</item>
+ <item quantity="many">Восстановление <xliff:g id="COUNT">^1</xliff:g> видео из корзины…</item>
+ <item quantity="other">Восстановление <xliff:g id="COUNT">^1</xliff:g> видео из корзины…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="one">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" восстановить <xliff:g id="COUNT">^2</xliff:g> фото из корзины?</item>
<item quantity="few">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" восстановить <xliff:g id="COUNT">^2</xliff:g> фото из корзины?</item>
<item quantity="many">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" восстановить <xliff:g id="COUNT">^2</xliff:g> фото из корзины?</item>
<item quantity="other">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" восстановить <xliff:g id="COUNT">^2</xliff:g> фото из корзины?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="one">Восстановление <xliff:g id="COUNT">^1</xliff:g> фотографии из корзины…</item>
+ <item quantity="few">Восстановление <xliff:g id="COUNT">^1</xliff:g> фотографий из корзины…</item>
+ <item quantity="many">Восстановление <xliff:g id="COUNT">^1</xliff:g> фотографий из корзины…</item>
+ <item quantity="other">Восстановление <xliff:g id="COUNT">^1</xliff:g> фотографии из корзины…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="one">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" восстановить <xliff:g id="COUNT">^2</xliff:g> объект из корзины?</item>
<item quantity="few">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" восстановить <xliff:g id="COUNT">^2</xliff:g> объекта из корзины?</item>
<item quantity="many">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" восстановить <xliff:g id="COUNT">^2</xliff:g> объектов из корзины?</item>
<item quantity="other">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" восстановить <xliff:g id="COUNT">^2</xliff:g> объекта из корзины?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="one">Восстановление <xliff:g id="COUNT">^1</xliff:g> объекта из корзины…</item>
+ <item quantity="few">Восстановление <xliff:g id="COUNT">^1</xliff:g> объектов из корзины…</item>
+ <item quantity="many">Восстановление <xliff:g id="COUNT">^1</xliff:g> объектов из корзины…</item>
+ <item quantity="other">Восстановление <xliff:g id="COUNT">^1</xliff:g> объекта из корзины…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="one">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" удалить <xliff:g id="COUNT">^2</xliff:g> аудиофайл?</item>
<item quantity="few">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" удалить <xliff:g id="COUNT">^2</xliff:g> аудиофайла?</item>
<item quantity="many">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" удалить <xliff:g id="COUNT">^2</xliff:g> аудиофайлов?</item>
<item quantity="other">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" удалить <xliff:g id="COUNT">^2</xliff:g> аудиофайла?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="one">Удаление <xliff:g id="COUNT">^1</xliff:g> аудиофайла…</item>
+ <item quantity="few">Удаление <xliff:g id="COUNT">^1</xliff:g> аудиофайлов…</item>
+ <item quantity="many">Удаление <xliff:g id="COUNT">^1</xliff:g> аудиофайлов…</item>
+ <item quantity="other">Удаление <xliff:g id="COUNT">^1</xliff:g> аудиофайла…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="one">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" удалить <xliff:g id="COUNT">^2</xliff:g> видео?</item>
<item quantity="few">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" удалить <xliff:g id="COUNT">^2</xliff:g> видео?</item>
<item quantity="many">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" удалить <xliff:g id="COUNT">^2</xliff:g> видео?</item>
<item quantity="other">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" удалить <xliff:g id="COUNT">^2</xliff:g> видео?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="one">Удаление <xliff:g id="COUNT">^1</xliff:g> видео…</item>
+ <item quantity="few">Удаление <xliff:g id="COUNT">^1</xliff:g> видео…</item>
+ <item quantity="many">Удаление <xliff:g id="COUNT">^1</xliff:g> видео…</item>
+ <item quantity="other">Удаление <xliff:g id="COUNT">^1</xliff:g> видео…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="one">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" удалить <xliff:g id="COUNT">^2</xliff:g> фото?</item>
<item quantity="few">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" удалить <xliff:g id="COUNT">^2</xliff:g> фото?</item>
<item quantity="many">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" удалить <xliff:g id="COUNT">^2</xliff:g> фото?</item>
<item quantity="other">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" удалить <xliff:g id="COUNT">^2</xliff:g> фото?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="one">Удаление <xliff:g id="COUNT">^1</xliff:g> фотографии…</item>
+ <item quantity="few">Удаление <xliff:g id="COUNT">^1</xliff:g> фотографий…</item>
+ <item quantity="many">Удаление <xliff:g id="COUNT">^1</xliff:g> фотографий…</item>
+ <item quantity="other">Удаление <xliff:g id="COUNT">^1</xliff:g> фотографии…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="one">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" удалить <xliff:g id="COUNT">^2</xliff:g> объект?</item>
<item quantity="few">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" удалить <xliff:g id="COUNT">^2</xliff:g> объекта?</item>
<item quantity="many">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" удалить <xliff:g id="COUNT">^2</xliff:g> объектов?</item>
<item quantity="other">Разрешить приложению \"<xliff:g id="APP_NAME_1">^1</xliff:g>\" удалить <xliff:g id="COUNT">^2</xliff:g> объекта?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="one">Удаление <xliff:g id="COUNT">^1</xliff:g> объекта…</item>
+ <item quantity="few">Удаление <xliff:g id="COUNT">^1</xliff:g> объектов…</item>
+ <item quantity="many">Удаление <xliff:g id="COUNT">^1</xliff:g> объектов…</item>
+ <item quantity="other">Удаление <xliff:g id="COUNT">^1</xliff:g> объекта…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"Приложение \"<xliff:g id="APP_NAME">%s</xliff:g>\" не может обрабатывать медиафайлы."</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Обработка медиафайла отменена."</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Произошла ошибка при обработке медиафайла."</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Обработка медиафайла завершена."</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Началась обработка медиафайла."</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Обработка медиафайла…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Отмена"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Подождать"</string>
</resources>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index ad22297..4b0b9bb 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -47,64 +47,136 @@
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ට ඕඩියෝ ගොනු <xliff:g id="COUNT">^2</xliff:g>ක් වෙනස් කිරීමට ඉඩ දෙන්නද?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ට ඕඩියෝ ගොනු <xliff:g id="COUNT">^2</xliff:g>ක් වෙනස් කිරීමට ඉඩ දෙන්නද?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="one">ශ්රව්ය ගොනු <xliff:g id="COUNT">^1</xliff:g>ක් වෙනස් කරමින්…</item>
+ <item quantity="other">ශ්රව්ය ගොනු <xliff:g id="COUNT">^1</xliff:g>ක් වෙනස් කරමින්…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ට වීඩියෝ <xliff:g id="COUNT">^2</xliff:g>ක් වෙනස් කිරීමට ඉඩ දෙන්නද?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ට වීඩියෝ <xliff:g id="COUNT">^2</xliff:g>ක් වෙනස් කිරීමට ඉඩ දෙන්නද?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="one">වීඩියෝ <xliff:g id="COUNT">^1</xliff:g>ක් වෙනස් කරමින්…</item>
+ <item quantity="other">වීඩියෝ <xliff:g id="COUNT">^1</xliff:g>ක් වෙනස් කරමින්…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ට ඡායාරූප <xliff:g id="COUNT">^2</xliff:g>ක් වෙනස් කිරීමට ඉඩ දෙන්නද?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ට ඡායාරූප <xliff:g id="COUNT">^2</xliff:g>ක් වෙනස් කිරීමට ඉඩ දෙන්නද?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="one">ඡායාරූප <xliff:g id="COUNT">^1</xliff:g>ක් වෙනස් කරමින්…</item>
+ <item quantity="other">ඡායාරූප <xliff:g id="COUNT">^1</xliff:g>ක් වෙනස් කරමින්…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ට අයිතම <xliff:g id="COUNT">^2</xliff:g>ක් වෙනස් කිරීමට ඉඩ දෙන්නද?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ට අයිතම <xliff:g id="COUNT">^2</xliff:g>ක් වෙනස් කිරීමට ඉඩ දෙන්නද?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="one">අයිතම <xliff:g id="COUNT">^1</xliff:g>ක් වෙනස් කරමින්…</item>
+ <item quantity="other">අයිතම <xliff:g id="COUNT">^1</xliff:g>ක් වෙනස් කරමින්…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ට ඕඩියෝ ගොනු <xliff:g id="COUNT">^2</xliff:g>ක් කුණු කුඩය වෙත ගෙන යාමට ඉඩ දෙන්නද?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ට ඕඩියෝ ගොනු <xliff:g id="COUNT">^2</xliff:g>ක් කුණු කුඩය වෙත ගෙන යාමට ඉඩ දෙන්නද?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="one">ශ්රව්ය ගොනු <xliff:g id="COUNT">^1</xliff:g>ක් කුණු කූඩය වෙත ගෙන යමින්…</item>
+ <item quantity="other">ශ්රව්ය ගොනු <xliff:g id="COUNT">^1</xliff:g>ක් කුණු කූඩය වෙත ගෙන යමින්…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ට වීඩියෝ <xliff:g id="COUNT">^2</xliff:g>ක් කුණු කුඩය වෙත ගෙන යාමට ඉඩ දෙන්නද?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ට වීඩියෝ <xliff:g id="COUNT">^2</xliff:g>ක් කුණු කුඩය වෙත ගෙන යාමට ඉඩ දෙන්නද?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="one">වීඩියෝ <xliff:g id="COUNT">^1</xliff:g>ක් කුණු කුඩය වෙත ගෙන යමින්…</item>
+ <item quantity="other">වීඩියෝ <xliff:g id="COUNT">^1</xliff:g>ක් කුණු කුඩය වෙත ගෙන යමින්…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ට ඡායාරූප <xliff:g id="COUNT">^2</xliff:g>ක් කුණු කුඩය වෙත ගෙන යාමට ඉඩ දෙන්නද?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ට ඡායාරූප <xliff:g id="COUNT">^2</xliff:g>ක් කුණු කුඩය වෙත ගෙන යාමට ඉඩ දෙන්නද?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="one">ඡායාරූප <xliff:g id="COUNT">^1</xliff:g>ක් කුණු කුඩය වෙත ගෙන යමින්…</item>
+ <item quantity="other">ඡායාරූප <xliff:g id="COUNT">^1</xliff:g>ක් කුණු කුඩය වෙත ගෙන යමින්…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ට අයිතම <xliff:g id="COUNT">^2</xliff:g>ක් කුණු කුඩය වෙත ගෙන යාමට ඉඩ දෙන්නද?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ට අයිතම <xliff:g id="COUNT">^2</xliff:g>ක් කුණු කුඩය වෙත ගෙන යාමට ඉඩ දෙන්නද?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="one">අයිතම <xliff:g id="COUNT">^1</xliff:g>ක් කුණු කුඩය වෙත ගෙන යමින්…</item>
+ <item quantity="other">අයිතම <xliff:g id="COUNT">^1</xliff:g>ක් කුණු කුඩය වෙත ගෙන යමින්…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ට ඕඩියෝ ගොනු <xliff:g id="COUNT">^2</xliff:g>ක් කුණු කුඩයෙන් පිටතට ගෙන යාමට ඉඩ දෙන්නද?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ට ඕඩියෝ ගොනු <xliff:g id="COUNT">^2</xliff:g>ක් කුණු කුඩයෙන් පිටතට ගෙන යාමට ඉඩ දෙන්නද?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="one">ශ්රව්ය ගොනු <xliff:g id="COUNT">^1</xliff:g>ක් කුණු කූඩයෙන් ඉවතට ගෙන යමින්…</item>
+ <item quantity="other">ශ්රව්ය ගොනු <xliff:g id="COUNT">^1</xliff:g>ක් කුණු කූඩයෙන් ඉවතට ගෙන යමින්…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ට වීඩියෝ <xliff:g id="COUNT">^2</xliff:g>ක් කුණු කුඩයෙන් පිටතට ගෙන යාමට ඉඩ දෙන්නද?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ට වීඩියෝ <xliff:g id="COUNT">^2</xliff:g>ක් කුණු කුඩයෙන් පිටතට ගෙන යාමට ඉඩ දෙන්නද?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="one">වීඩියෝ <xliff:g id="COUNT">^1</xliff:g>ක් කුණු කූඩයෙන් ඉවතට ගෙන යමින්…</item>
+ <item quantity="other">වීඩියෝ <xliff:g id="COUNT">^1</xliff:g>ක් කුණු කූඩයෙන් ඉවතට ගෙන යමින්…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ට ඡායාරූප <xliff:g id="COUNT">^2</xliff:g>ක් කුණු කුඩයෙන් පිටතට ගෙන යාමට ඉඩ දෙන්නද?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ට ඡායාරූප <xliff:g id="COUNT">^2</xliff:g>ක් කුණු කුඩයෙන් පිටතට ගෙන යාමට ඉඩ දෙන්නද?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="one">ඡායාරූප <xliff:g id="COUNT">^1</xliff:g>ක් කුණු කූඩයෙන් ඉවතට ගෙන යමින්…</item>
+ <item quantity="other">ඡායාරූප <xliff:g id="COUNT">^1</xliff:g>ක් කුණු කූඩයෙන් ඉවතට ගෙන යමින්…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ට අයිතම <xliff:g id="COUNT">^2</xliff:g>ක් කුණු කුඩයෙන් පිටතට ගෙන යාමට ඉඩ දෙන්නද?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ට අයිතම <xliff:g id="COUNT">^2</xliff:g>ක් කුණු කුඩයෙන් පිටතට ගෙන යාමට ඉඩ දෙන්නද?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="one">අයිතම <xliff:g id="COUNT">^1</xliff:g>ක් කුණු කූඩයෙන් ඉවතට ගෙන යමින්…</item>
+ <item quantity="other">අයිතම <xliff:g id="COUNT">^1</xliff:g>ක් කුණු කූඩයෙන් ඉවතට ගෙන යමින්…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ට ඕඩියෝ ගොනු <xliff:g id="COUNT">^2</xliff:g>ක් මැකීමට ඉඩ දෙන්නද?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ට ඕඩියෝ ගොනු <xliff:g id="COUNT">^2</xliff:g>ක් මැකීමට ඉඩ දෙන්නද?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="one">ශ්රව්ය ගොනු <xliff:g id="COUNT">^1</xliff:g>ක් මකමින්…</item>
+ <item quantity="other">ශ්රව්ය ගොනු <xliff:g id="COUNT">^1</xliff:g>ක් මකමින්…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ට වීඩියෝ <xliff:g id="COUNT">^2</xliff:g>ක් මැකීමට ඉඩ දෙන්නද?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ට වීඩියෝ <xliff:g id="COUNT">^2</xliff:g>ක් මැකීමට ඉඩ දෙන්නද?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="one">වීඩියෝ <xliff:g id="COUNT">^1</xliff:g>ක් මකමින්…</item>
+ <item quantity="other">වීඩියෝ <xliff:g id="COUNT">^1</xliff:g>ක් මකමින්…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ට ඡායාරූප <xliff:g id="COUNT">^2</xliff:g>ක් මැකීමට ඉඩ දෙන්නද?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ට ඡායාරූප <xliff:g id="COUNT">^2</xliff:g>ක් මැකීමට ඉඩ දෙන්නද?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="one">ඡායාරූප <xliff:g id="COUNT">^1</xliff:g>ක් මකමින්…</item>
+ <item quantity="other">ඡායාරූප <xliff:g id="COUNT">^1</xliff:g>ක් මකමින්…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="one"><xliff:g id="APP_NAME_1">^1</xliff:g>ට අයිතම <xliff:g id="COUNT">^2</xliff:g>ක් මැකීමට ඉඩ දෙන්නද?</item>
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g>ට අයිතම <xliff:g id="COUNT">^2</xliff:g>ක් මැකීමට ඉඩ දෙන්නද?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="one">අයිතම <xliff:g id="COUNT">^1</xliff:g>ක් මකමින්…</item>
+ <item quantity="other">අයිතම <xliff:g id="COUNT">^1</xliff:g>ක් මකමින්…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> හට මාධ්ය ගොනු සැකසිය නොහැකිය"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"මාධ්ය සැකසීම අවලංගු කරන ලදී"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"මාධ්ය සැකසීමේ දෝෂය"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"මාධ්ය සැකසීම සාර්ථකයි"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"මාධ්ය සැකසීම ආරම්භ විය"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"මාධ්යය සකසමින්…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"අවලංගු කරන්න"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"රැඳී සිටින්න"</string>
</resources>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 359ba24..fc0ea6b 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -53,94 +53,198 @@
<item quantity="other">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> upraviť <xliff:g id="COUNT">^2</xliff:g> zvukových súborov?</item>
<item quantity="one">Chcete povoliť aplikácii <xliff:g id="APP_NAME_0">^1</xliff:g> upraviť tento zvukový súbor?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="few">Upravujú sa <xliff:g id="COUNT">^1</xliff:g> zvukové súbory…</item>
+ <item quantity="many">Modifying <xliff:g id="COUNT">^1</xliff:g> audio files…</item>
+ <item quantity="other">Upravuje sa <xliff:g id="COUNT">^1</xliff:g> zvukových súborov…</item>
+ <item quantity="one">Upravuje sa zvukový súbor…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="few">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> upraviť <xliff:g id="COUNT">^2</xliff:g> videá?</item>
<item quantity="many">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to modify <xliff:g id="COUNT">^2</xliff:g> videos?</item>
<item quantity="other">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> upraviť <xliff:g id="COUNT">^2</xliff:g> videí?</item>
<item quantity="one">Chcete povoliť aplikácii <xliff:g id="APP_NAME_0">^1</xliff:g> upraviť toto video?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="few">Upravujú sa <xliff:g id="COUNT">^1</xliff:g> videá…</item>
+ <item quantity="many">Modifying <xliff:g id="COUNT">^1</xliff:g> videos…</item>
+ <item quantity="other">Upravuje sa <xliff:g id="COUNT">^1</xliff:g> videí…</item>
+ <item quantity="one">Upravuje sa video…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="few">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> upraviť <xliff:g id="COUNT">^2</xliff:g> fotky?</item>
<item quantity="many">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to modify <xliff:g id="COUNT">^2</xliff:g> photos?</item>
<item quantity="other">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> upraviť <xliff:g id="COUNT">^2</xliff:g> fotiek?</item>
<item quantity="one">Chcete povoliť aplikácii <xliff:g id="APP_NAME_0">^1</xliff:g> upraviť túto fotku?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="few">Upravujú sa <xliff:g id="COUNT">^1</xliff:g> fotky…</item>
+ <item quantity="many">Modifying <xliff:g id="COUNT">^1</xliff:g> photos…</item>
+ <item quantity="other">Upravuje sa <xliff:g id="COUNT">^1</xliff:g> fotiek…</item>
+ <item quantity="one">Upravuje sa fotka…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="few">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> upraviť <xliff:g id="COUNT">^2</xliff:g> položky?</item>
<item quantity="many">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to modify <xliff:g id="COUNT">^2</xliff:g> items?</item>
<item quantity="other">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> upraviť <xliff:g id="COUNT">^2</xliff:g> položiek?</item>
<item quantity="one">Chcete povoliť aplikácii <xliff:g id="APP_NAME_0">^1</xliff:g> upraviť túto položku?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="few">Upravujú sa <xliff:g id="COUNT">^1</xliff:g> položky…</item>
+ <item quantity="many">Modifying <xliff:g id="COUNT">^1</xliff:g> items…</item>
+ <item quantity="other">Upravuje sa <xliff:g id="COUNT">^1</xliff:g> položiek…</item>
+ <item quantity="one">Upravuje sa položka…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="few">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> presunúť <xliff:g id="COUNT">^2</xliff:g> zvukové súbory do koša?</item>
<item quantity="many">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> audio files to trash?</item>
<item quantity="other">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> presunúť <xliff:g id="COUNT">^2</xliff:g> zvukových súborov do koša?</item>
<item quantity="one">Chcete povoliť aplikácii <xliff:g id="APP_NAME_0">^1</xliff:g> presunúť tento zvukový súbor do koša?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> zvukové súbory sa presúvajú do koša…</item>
+ <item quantity="many">Moving <xliff:g id="COUNT">^1</xliff:g> audio files to trash…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> zvukových súborov sa presúva do koša…</item>
+ <item quantity="one">Zvukový súbor sa presúva do koša…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="few">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> presunúť <xliff:g id="COUNT">^2</xliff:g> videá do koša?</item>
<item quantity="many">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> videos to trash?</item>
<item quantity="other">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> presunúť <xliff:g id="COUNT">^2</xliff:g> videí do koša?</item>
<item quantity="one">Chcete povoliť aplikácii <xliff:g id="APP_NAME_0">^1</xliff:g> presunúť toto video do koša?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> videá sa presúvajú do koša…</item>
+ <item quantity="many">Moving <xliff:g id="COUNT">^1</xliff:g> videos to trash…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> videí sa presúva do koša…</item>
+ <item quantity="one">Video sa presúva do koša…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="few">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> presunúť <xliff:g id="COUNT">^2</xliff:g> fotky do koša?</item>
<item quantity="many">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> photos to trash?</item>
<item quantity="other">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> presunúť <xliff:g id="COUNT">^2</xliff:g> fotiek do koša?</item>
<item quantity="one">Chcete povoliť aplikácii <xliff:g id="APP_NAME_0">^1</xliff:g> presunúť túto fotku do koša?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> fotky sa presúvajú do koša…</item>
+ <item quantity="many">Moving <xliff:g id="COUNT">^1</xliff:g> photos to trash…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> fotiek sa presúva do koša…</item>
+ <item quantity="one">Fotka sa presúva do koša…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="few">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> presunúť <xliff:g id="COUNT">^2</xliff:g> položky do koša?</item>
<item quantity="many">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> items to trash?</item>
<item quantity="other">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> presunúť <xliff:g id="COUNT">^2</xliff:g> položiek do koša?</item>
<item quantity="one">Chcete povoliť aplikácii <xliff:g id="APP_NAME_0">^1</xliff:g> presunúť túto položku do koša?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> položky sa presúvajú do koša…</item>
+ <item quantity="many">Moving <xliff:g id="COUNT">^1</xliff:g> items to trash…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> položiek sa presúva do koša…</item>
+ <item quantity="one">Položka sa presúva do koša…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="few">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> presunúť <xliff:g id="COUNT">^2</xliff:g> zvukové súbory z koša?</item>
<item quantity="many">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> audio files out of trash?</item>
<item quantity="other">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> presunúť <xliff:g id="COUNT">^2</xliff:g> zvukových súborov z koša?</item>
<item quantity="one">Chcete povoliť aplikácii <xliff:g id="APP_NAME_0">^1</xliff:g> presunúť tento zvukový súbor z koša?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> zvukové súbory sa presúvajú z koša…</item>
+ <item quantity="many">Moving <xliff:g id="COUNT">^1</xliff:g> audio files out of trash…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> zvukových súborov sa presúva z koša…</item>
+ <item quantity="one">Zvukový súbor sa presúva z koša…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="few">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> presunúť <xliff:g id="COUNT">^2</xliff:g> videá z koša?</item>
<item quantity="many">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> videos out of trash?</item>
<item quantity="other">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> presunúť <xliff:g id="COUNT">^2</xliff:g> videí z koša?</item>
<item quantity="one">Chcete povoliť aplikácii <xliff:g id="APP_NAME_0">^1</xliff:g> presunúť toto video z koša?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> videá sa presúvajú z koša…</item>
+ <item quantity="many">Moving <xliff:g id="COUNT">^1</xliff:g> videos out of trash…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> videí sa presúva z koša…</item>
+ <item quantity="one">Video sa presúva z koša…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="few">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> presunúť <xliff:g id="COUNT">^2</xliff:g> fotky z koša?</item>
<item quantity="many">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> photos out of trash?</item>
<item quantity="other">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> presunúť <xliff:g id="COUNT">^2</xliff:g> fotiek z koša?</item>
<item quantity="one">Chcete povoliť aplikácii <xliff:g id="APP_NAME_0">^1</xliff:g> presunúť túto fotku z koša?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> fotky sa presúvajú z koša…</item>
+ <item quantity="many">Moving <xliff:g id="COUNT">^1</xliff:g> photos out of trash…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> fotiek sa presúva z koša…</item>
+ <item quantity="one">Fotka sa presúva z koša…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="few">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> presunúť <xliff:g id="COUNT">^2</xliff:g> položky z koša?</item>
<item quantity="many">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to move <xliff:g id="COUNT">^2</xliff:g> items out of trash?</item>
<item quantity="other">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> presunúť <xliff:g id="COUNT">^2</xliff:g> položiek z koša?</item>
<item quantity="one">Chcete povoliť aplikácii <xliff:g id="APP_NAME_0">^1</xliff:g> presunúť túto položku z koša?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> položky sa presúvajú z koša…</item>
+ <item quantity="many">Moving <xliff:g id="COUNT">^1</xliff:g> items out of trash…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> položiek sa presúva z koša…</item>
+ <item quantity="one">Položka sa presúva z koša…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="few">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> odstrániť <xliff:g id="COUNT">^2</xliff:g> zvukové súbory?</item>
<item quantity="many">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to delete <xliff:g id="COUNT">^2</xliff:g> audio files?</item>
<item quantity="other">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> odstrániť <xliff:g id="COUNT">^2</xliff:g> zvukových súborov?</item>
<item quantity="one">Chcete povoliť aplikácii <xliff:g id="APP_NAME_0">^1</xliff:g> odstrániť tento zvukový súbor?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="few">Odstraňujú sa <xliff:g id="COUNT">^1</xliff:g> zvukové súbory…</item>
+ <item quantity="many">Deleting <xliff:g id="COUNT">^1</xliff:g> audio files…</item>
+ <item quantity="other">Odstraňuje sa <xliff:g id="COUNT">^1</xliff:g> zvukových súborov…</item>
+ <item quantity="one">Odstraňuje sa zvukový súbor…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="few">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> odstrániť <xliff:g id="COUNT">^2</xliff:g> videá?</item>
<item quantity="many">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to delete <xliff:g id="COUNT">^2</xliff:g> videos?</item>
<item quantity="other">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> odstrániť <xliff:g id="COUNT">^2</xliff:g> videí?</item>
<item quantity="one">Chcete povoliť aplikácii <xliff:g id="APP_NAME_0">^1</xliff:g> odstrániť toto video?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="few">Odstraňujú sa <xliff:g id="COUNT">^1</xliff:g> videá…</item>
+ <item quantity="many">Deleting <xliff:g id="COUNT">^1</xliff:g> videos…</item>
+ <item quantity="other">Odstraňuje sa <xliff:g id="COUNT">^1</xliff:g> videí…</item>
+ <item quantity="one">Odstraňuje sa video…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="few">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> odstrániť <xliff:g id="COUNT">^2</xliff:g> fotky?</item>
<item quantity="many">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to delete <xliff:g id="COUNT">^2</xliff:g> photos?</item>
<item quantity="other">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> odstrániť <xliff:g id="COUNT">^2</xliff:g> fotiek?</item>
<item quantity="one">Chcete povoliť aplikácii <xliff:g id="APP_NAME_0">^1</xliff:g> odstrániť túto fotku?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="few">Odstraňujú sa <xliff:g id="COUNT">^1</xliff:g> fotky…</item>
+ <item quantity="many">Deleting <xliff:g id="COUNT">^1</xliff:g> photos…</item>
+ <item quantity="other">Odstraňuje sa <xliff:g id="COUNT">^1</xliff:g> fotiek…</item>
+ <item quantity="one">Odstraňuje sa fotka…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="few">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> odstrániť <xliff:g id="COUNT">^2</xliff:g> položky?</item>
<item quantity="many">Allow <xliff:g id="APP_NAME_1">^1</xliff:g> to delete <xliff:g id="COUNT">^2</xliff:g> items?</item>
<item quantity="other">Chcete povoliť aplikácii <xliff:g id="APP_NAME_1">^1</xliff:g> odstrániť <xliff:g id="COUNT">^2</xliff:g> položiek?</item>
<item quantity="one">Chcete povoliť aplikácii <xliff:g id="APP_NAME_0">^1</xliff:g> odstrániť túto položku?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="few">Odstraňujú sa <xliff:g id="COUNT">^1</xliff:g> položky…</item>
+ <item quantity="many">Deleting <xliff:g id="COUNT">^1</xliff:g> items…</item>
+ <item quantity="other">Odstraňuje sa <xliff:g id="COUNT">^1</xliff:g> položiek…</item>
+ <item quantity="one">Odstraňuje sa položka…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> nemôže spracúvať súbory médií"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Spracúvanie médií bolo zrušené"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Pri spracúvaní médií sa vyskytla chyba"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Médiá boli úspešne spracované"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Spracúvanie médií sa začalo"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Spracúvajú sa médiá…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Zrušiť"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Počkať"</string>
</resources>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index ff63498..d4ac3a1 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -53,94 +53,198 @@
<item quantity="few">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da spremeni <xliff:g id="COUNT">^2</xliff:g> zvočne datoteke?</item>
<item quantity="other">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da spremeni <xliff:g id="COUNT">^2</xliff:g> zvočnih datotek?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="one">Spreminjanje <xliff:g id="COUNT">^1</xliff:g> zvočne datoteke …</item>
+ <item quantity="two">Spreminjanje <xliff:g id="COUNT">^1</xliff:g> zvočnih datotek …</item>
+ <item quantity="few">Spreminjanje <xliff:g id="COUNT">^1</xliff:g> zvočnih datotek …</item>
+ <item quantity="other">Spreminjanje <xliff:g id="COUNT">^1</xliff:g> zvočnih datotek …</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="one">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da spremeni <xliff:g id="COUNT">^2</xliff:g> videoposnetek?</item>
<item quantity="two">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da spremeni <xliff:g id="COUNT">^2</xliff:g> videoposnetka?</item>
<item quantity="few">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da spremeni <xliff:g id="COUNT">^2</xliff:g> videoposnetke?</item>
<item quantity="other">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da spremeni <xliff:g id="COUNT">^2</xliff:g> videoposnetkov?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="one">Spreminjanje <xliff:g id="COUNT">^1</xliff:g> videoposnetka …</item>
+ <item quantity="two">Spreminjanje <xliff:g id="COUNT">^1</xliff:g> videoposnetkov …</item>
+ <item quantity="few">Spreminjanje <xliff:g id="COUNT">^1</xliff:g> videoposnetkov …</item>
+ <item quantity="other">Spreminjanje <xliff:g id="COUNT">^1</xliff:g> videoposnetkov …</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="one">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da spremeni <xliff:g id="COUNT">^2</xliff:g> fotografijo?</item>
<item quantity="two">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da spremeni <xliff:g id="COUNT">^2</xliff:g> fotografiji?</item>
<item quantity="few">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da spremeni <xliff:g id="COUNT">^2</xliff:g> fotografije?</item>
<item quantity="other">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da spremeni <xliff:g id="COUNT">^2</xliff:g> fotografij?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="one">Spreminjanje <xliff:g id="COUNT">^1</xliff:g> fotografije …</item>
+ <item quantity="two">Spreminjanje <xliff:g id="COUNT">^1</xliff:g> fotografij …</item>
+ <item quantity="few">Spreminjanje <xliff:g id="COUNT">^1</xliff:g> fotografij …</item>
+ <item quantity="other">Spreminjanje <xliff:g id="COUNT">^1</xliff:g> fotografij …</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="one">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da spremeni <xliff:g id="COUNT">^2</xliff:g> element?</item>
<item quantity="two">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da spremeni <xliff:g id="COUNT">^2</xliff:g> elementa?</item>
<item quantity="few">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da spremeni <xliff:g id="COUNT">^2</xliff:g> elemente?</item>
<item quantity="other">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da spremeni <xliff:g id="COUNT">^2</xliff:g> elementov?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="one">Spreminjanje <xliff:g id="COUNT">^1</xliff:g> elementa …</item>
+ <item quantity="two">Spreminjanje <xliff:g id="COUNT">^1</xliff:g> elementov …</item>
+ <item quantity="few">Spreminjanje <xliff:g id="COUNT">^1</xliff:g> elementov …</item>
+ <item quantity="other">Spreminjanje <xliff:g id="COUNT">^1</xliff:g> elementov …</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="one">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> zvočno datoteko v smetnjak?</item>
<item quantity="two">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> zvočni datoteki v smetnjak?</item>
<item quantity="few">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> zvočne datoteke v smetnjak?</item>
<item quantity="other">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> zvočnih datotek v smetnjak?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="one">Premikanje <xliff:g id="COUNT">^1</xliff:g> zvočne datoteke v smetnjak …</item>
+ <item quantity="two">Premikanje <xliff:g id="COUNT">^1</xliff:g> zvočnih datotek v smetnjak …</item>
+ <item quantity="few">Premikanje <xliff:g id="COUNT">^1</xliff:g> zvočnih datotek v smetnjak …</item>
+ <item quantity="other">Premikanje <xliff:g id="COUNT">^1</xliff:g> zvočnih datotek v smetnjak …</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="one">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> videoposnetek v smetnjak?</item>
<item quantity="two">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> videoposnetka v smetnjak?</item>
<item quantity="few">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> videoposnetke v smetnjak?</item>
<item quantity="other">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> videoposnetkov v smetnjak?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="one">Premikanje <xliff:g id="COUNT">^1</xliff:g> videoposnetka v smetnjak …</item>
+ <item quantity="two">Premikanje <xliff:g id="COUNT">^1</xliff:g> videoposnetkov v smetnjak …</item>
+ <item quantity="few">Premikanje <xliff:g id="COUNT">^1</xliff:g> videoposnetkov v smetnjak …</item>
+ <item quantity="other">Premikanje <xliff:g id="COUNT">^1</xliff:g> videoposnetkov v smetnjak …</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="one">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> fotografijo v smetnjak?</item>
<item quantity="two">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> fotografiji v smetnjak?</item>
<item quantity="few">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> fotografije v smetnjak?</item>
<item quantity="other">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> fotografij v smetnjak?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="one">Premikanje <xliff:g id="COUNT">^1</xliff:g> fotografije v smetnjak …</item>
+ <item quantity="two">Premikanje <xliff:g id="COUNT">^1</xliff:g> fotografij v smetnjak …</item>
+ <item quantity="few">Premikanje <xliff:g id="COUNT">^1</xliff:g> fotografij v smetnjak …</item>
+ <item quantity="other">Premikanje <xliff:g id="COUNT">^1</xliff:g> fotografij v smetnjak …</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="one">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> element v smetnjak?</item>
<item quantity="two">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> elementa v smetnjak?</item>
<item quantity="few">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> elemente v smetnjak?</item>
<item quantity="other">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> elementov v smetnjak?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="one">Premikanje <xliff:g id="COUNT">^1</xliff:g> elementa v smetnjak …</item>
+ <item quantity="two">Premikanje <xliff:g id="COUNT">^1</xliff:g> elementov v smetnjak …</item>
+ <item quantity="few">Premikanje <xliff:g id="COUNT">^1</xliff:g> elementov v smetnjak …</item>
+ <item quantity="other">Premikanje <xliff:g id="COUNT">^1</xliff:g> elementov v smetnjak …</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="one">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> zvočno datoteko iz smetnjaka?</item>
<item quantity="two">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> zvočni datoteki iz smetnjaka?</item>
<item quantity="few">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> zvočne datoteke iz smetnjaka?</item>
<item quantity="other">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> zvočnih datotek iz smetnjaka?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="one">Premikanje <xliff:g id="COUNT">^1</xliff:g> zvočne datoteke iz smetnjaka …</item>
+ <item quantity="two">Premikanje <xliff:g id="COUNT">^1</xliff:g> zvočnih datotek iz smetnjaka …</item>
+ <item quantity="few">Premikanje <xliff:g id="COUNT">^1</xliff:g> zvočnih datotek iz smetnjaka …</item>
+ <item quantity="other">Premikanje <xliff:g id="COUNT">^1</xliff:g> zvočnih datotek iz smetnjaka …</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="one">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> videoposnetek iz smetnjaka?</item>
<item quantity="two">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> videoposnetka iz smetnjaka?</item>
<item quantity="few">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> videoposnetke iz smetnjaka?</item>
<item quantity="other">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> videoposnetkov iz smetnjaka?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="one">Premikanje <xliff:g id="COUNT">^1</xliff:g> videoposnetka iz smetnjaka …</item>
+ <item quantity="two">Premikanje <xliff:g id="COUNT">^1</xliff:g> videoposnetkov iz smetnjaka …</item>
+ <item quantity="few">Premikanje <xliff:g id="COUNT">^1</xliff:g> videoposnetkov iz smetnjaka …</item>
+ <item quantity="other">Premikanje <xliff:g id="COUNT">^1</xliff:g> videoposnetkov iz smetnjaka …</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="one">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> fotografijo iz smetnjaka?</item>
<item quantity="two">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> fotografiji iz smetnjaka?</item>
<item quantity="few">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> fotografije iz smetnjaka?</item>
<item quantity="other">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> fotografij iz smetnjaka?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="one">Premikanje <xliff:g id="COUNT">^1</xliff:g> fotografije iz smetnjaka …</item>
+ <item quantity="two">Premikanje <xliff:g id="COUNT">^1</xliff:g> fotografij iz smetnjaka …</item>
+ <item quantity="few">Premikanje <xliff:g id="COUNT">^1</xliff:g> fotografij iz smetnjaka …</item>
+ <item quantity="other">Premikanje <xliff:g id="COUNT">^1</xliff:g> fotografij iz smetnjaka …</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="one">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> element iz smetnjaka?</item>
<item quantity="two">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> elementa iz smetnjaka?</item>
<item quantity="few">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> elemente iz smetnjaka?</item>
<item quantity="other">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da premakne <xliff:g id="COUNT">^2</xliff:g> elementov iz smetnjaka?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="one">Premikanje <xliff:g id="COUNT">^1</xliff:g> elementa iz smetnjaka …</item>
+ <item quantity="two">Premikanje <xliff:g id="COUNT">^1</xliff:g> elementov iz smetnjaka …</item>
+ <item quantity="few">Premikanje <xliff:g id="COUNT">^1</xliff:g> elementov iz smetnjaka …</item>
+ <item quantity="other">Premikanje <xliff:g id="COUNT">^1</xliff:g> elementov iz smetnjaka …</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="one">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da izbriše <xliff:g id="COUNT">^2</xliff:g> zvočno datoteko?</item>
<item quantity="two">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da izbriše <xliff:g id="COUNT">^2</xliff:g> zvočni datoteki?</item>
<item quantity="few">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da izbriše <xliff:g id="COUNT">^2</xliff:g> zvočne datoteke?</item>
<item quantity="other">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da izbriše <xliff:g id="COUNT">^2</xliff:g> zvočnih datotek?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="one">Brisanje <xliff:g id="COUNT">^1</xliff:g> zvočne datoteke …</item>
+ <item quantity="two">Brisanje <xliff:g id="COUNT">^1</xliff:g> zvočnih datotek …</item>
+ <item quantity="few">Brisanje <xliff:g id="COUNT">^1</xliff:g> zvočnih datotek …</item>
+ <item quantity="other">Brisanje <xliff:g id="COUNT">^1</xliff:g> zvočnih datotek …</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="one">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da izbriše <xliff:g id="COUNT">^2</xliff:g> videoposnetek?</item>
<item quantity="two">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da izbriše <xliff:g id="COUNT">^2</xliff:g> videoposnetka?</item>
<item quantity="few">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da izbriše <xliff:g id="COUNT">^2</xliff:g> videoposnetke?</item>
<item quantity="other">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da izbriše <xliff:g id="COUNT">^2</xliff:g> videoposnetkov?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="one">Brisanje <xliff:g id="COUNT">^1</xliff:g> videoposnetka …</item>
+ <item quantity="two">Brisanje <xliff:g id="COUNT">^1</xliff:g> videoposnetkov …</item>
+ <item quantity="few">Brisanje <xliff:g id="COUNT">^1</xliff:g> videoposnetkov …</item>
+ <item quantity="other">Brisanje <xliff:g id="COUNT">^1</xliff:g> videoposnetkov …</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="one">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da izbriše <xliff:g id="COUNT">^2</xliff:g> fotografijo?</item>
<item quantity="two">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da izbriše <xliff:g id="COUNT">^2</xliff:g> fotografiji?</item>
<item quantity="few">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da izbriše <xliff:g id="COUNT">^2</xliff:g> fotografije?</item>
<item quantity="other">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da izbriše <xliff:g id="COUNT">^2</xliff:g> fotografij?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="one">Brisanje <xliff:g id="COUNT">^1</xliff:g> fotografije …</item>
+ <item quantity="two">Brisanje <xliff:g id="COUNT">^1</xliff:g> fotografij …</item>
+ <item quantity="few">Brisanje <xliff:g id="COUNT">^1</xliff:g> fotografij …</item>
+ <item quantity="other">Brisanje <xliff:g id="COUNT">^1</xliff:g> fotografij …</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="one">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da izbriše <xliff:g id="COUNT">^2</xliff:g> element?</item>
<item quantity="two">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da izbriše <xliff:g id="COUNT">^2</xliff:g> elementa?</item>
<item quantity="few">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da izbriše <xliff:g id="COUNT">^2</xliff:g> elemente?</item>
<item quantity="other">Želite dovoliti aplikaciji <xliff:g id="APP_NAME_1">^1</xliff:g>, da izbriše <xliff:g id="COUNT">^2</xliff:g> elementov?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="one">Brisanje <xliff:g id="COUNT">^1</xliff:g> elementa …</item>
+ <item quantity="two">Brisanje <xliff:g id="COUNT">^1</xliff:g> elementov …</item>
+ <item quantity="few">Brisanje <xliff:g id="COUNT">^1</xliff:g> elementov …</item>
+ <item quantity="other">Brisanje <xliff:g id="COUNT">^1</xliff:g> elementov …</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> ne more obdelati predstavnostnih datotek."</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Obdelava predstavnosti je preklicana."</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Napaka pri obdelavi predstavnosti"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Obdelava predstavnosti je uspešno dokončana."</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Obdelava predstavnosti se je začela."</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Obdelovanje predstavnosti …"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Prekliči"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Počakaj"</string>
</resources>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 1e90f35..d69a10c 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">Të lejohet <xliff:g id="APP_NAME_1">^1</xliff:g> që të modifikojë <xliff:g id="COUNT">^2</xliff:g> skedarë audio?</item>
<item quantity="one">Të lejohet <xliff:g id="APP_NAME_0">^1</xliff:g> që ta modifikojë këtë skedar audio?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> skedarë audio po modifikohen…</item>
+ <item quantity="one">Një skedar audio po modifikohet…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">Të lejohet <xliff:g id="APP_NAME_1">^1</xliff:g> që të modifikojë <xliff:g id="COUNT">^2</xliff:g> video?</item>
<item quantity="one">Të lejohet <xliff:g id="APP_NAME_0">^1</xliff:g> që ta modifikojë këtë video?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> video po modifikohen…</item>
+ <item quantity="one">Një video po modifikohet…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">Të lejohet <xliff:g id="APP_NAME_1">^1</xliff:g> që të modifikojë <xliff:g id="COUNT">^2</xliff:g> fotografi?</item>
<item quantity="one">Të lejohet <xliff:g id="APP_NAME_0">^1</xliff:g> që ta modifikojë këtë fotografi?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> fotografi po modifikohen…</item>
+ <item quantity="one">Një fotografi po modifikohet…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">Të lejohet <xliff:g id="APP_NAME_1">^1</xliff:g> që të modifikojë <xliff:g id="COUNT">^2</xliff:g> artikuj?</item>
<item quantity="one">Të lejohet <xliff:g id="APP_NAME_0">^1</xliff:g> që ta modifikojë këtë artikull?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> artikuj po modifikohen…</item>
+ <item quantity="one">Një artikull po modifikohet…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">Të lejohet <xliff:g id="APP_NAME_1">^1</xliff:g> që të zhvendosë <xliff:g id="COUNT">^2</xliff:g> skedarë audio te koshi?</item>
<item quantity="one">Të lejohet <xliff:g id="APP_NAME_0">^1</xliff:g> që ta zhvendosë këtë skedar audio te koshi?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> skedarë audio po zhvendosen te koshi…</item>
+ <item quantity="one">Një skedar audio po zhvendoset te koshi…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">Të lejohet <xliff:g id="APP_NAME_1">^1</xliff:g> që të zhvendosë <xliff:g id="COUNT">^2</xliff:g> video te koshi?</item>
<item quantity="one">Të lejohet <xliff:g id="APP_NAME_0">^1</xliff:g> që ta zhvendosë këtë video te koshi?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> video po zhvendosen te koshi…</item>
+ <item quantity="one">Një video po zhvendoset te koshi…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">Të lejohet <xliff:g id="APP_NAME_1">^1</xliff:g> që të zhvendosë <xliff:g id="COUNT">^2</xliff:g> fotografi te koshi?</item>
<item quantity="one">Të lejohet <xliff:g id="APP_NAME_0">^1</xliff:g> që ta zhvendosë këtë fotografi te koshi?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> fotografi po zhvendosen te koshi…</item>
+ <item quantity="one">Një fotografi po zhvendoset te koshi…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">Të lejohet <xliff:g id="APP_NAME_1">^1</xliff:g> që të zhvendosë <xliff:g id="COUNT">^2</xliff:g> artikuj te koshi?</item>
<item quantity="one">Të lejohet <xliff:g id="APP_NAME_0">^1</xliff:g> që ta zhvendosë këtë artikull te koshi?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> artikuj po zhvendosen te koshi…</item>
+ <item quantity="one">Një artikull po zhvendoset te koshi…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">Të lejohet <xliff:g id="APP_NAME_1">^1</xliff:g> që të zhvendosë <xliff:g id="COUNT">^2</xliff:g> skedarë audio nga koshi?</item>
<item quantity="one">Të lejohet <xliff:g id="APP_NAME_0">^1</xliff:g> që ta zhvendosë këtë skedar audio nga koshi?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> skedarë audio po zhvendosen nga koshi…</item>
+ <item quantity="one">Një skedar audio po zhvendoset nga koshi…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">Të lejohet <xliff:g id="APP_NAME_1">^1</xliff:g> që të zhvendosë <xliff:g id="COUNT">^2</xliff:g> video nga koshi?</item>
<item quantity="one">Të lejohet <xliff:g id="APP_NAME_0">^1</xliff:g> që ta zhvendosë këtë video nga koshi?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> video po zhvendosen nga koshi…</item>
+ <item quantity="one">Një video po zhvendoset nga koshi…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">Të lejohet <xliff:g id="APP_NAME_1">^1</xliff:g> që të zhvendosë <xliff:g id="COUNT">^2</xliff:g> fotografi nga koshi?</item>
<item quantity="one">Të lejohet <xliff:g id="APP_NAME_0">^1</xliff:g> që ta zhvendosë këtë fotografi nga koshi?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> fotografi po zhvendosen nga koshi…</item>
+ <item quantity="one">Një fotografi po zhvendoset nga koshi…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">Të lejohet <xliff:g id="APP_NAME_1">^1</xliff:g> që të zhvendosë <xliff:g id="COUNT">^2</xliff:g> artikuj nga koshi?</item>
<item quantity="one">Të lejohet <xliff:g id="APP_NAME_0">^1</xliff:g> që ta zhvendosë këtë artikull nga koshi?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> artikuj po zhvendosen nga koshi…</item>
+ <item quantity="one">Një artikull po zhvendoset nga koshi…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">Të lejohet <xliff:g id="APP_NAME_1">^1</xliff:g> që të fshijë <xliff:g id="COUNT">^2</xliff:g> skedarë audio?</item>
<item quantity="one">Të lejohet <xliff:g id="APP_NAME_0">^1</xliff:g> që të fshijë këtë skedar audio?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> skedarë audio po fshihen…</item>
+ <item quantity="one">Një skedar audio po fshihet…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">Të lejohet <xliff:g id="APP_NAME_1">^1</xliff:g> që të fshijë <xliff:g id="COUNT">^2</xliff:g> video?</item>
<item quantity="one">Të lejohet që <xliff:g id="APP_NAME_0">^1</xliff:g> ta fshijë këtë video?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> video po fshihen…</item>
+ <item quantity="one">Një video po fshihet…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">Të lejohet <xliff:g id="APP_NAME_1">^1</xliff:g> që të fshijë <xliff:g id="COUNT">^2</xliff:g> fotografi?</item>
<item quantity="one">Të lejohet që <xliff:g id="APP_NAME_0">^1</xliff:g> ta fshijë këtë fotografi?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> fotografi po fshihen…</item>
+ <item quantity="one">Një fotografi po fshihet…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">Të lejohet <xliff:g id="APP_NAME_1">^1</xliff:g> që të fshijë <xliff:g id="COUNT">^2</xliff:g> artikuj?</item>
<item quantity="one">Të lejohet që <xliff:g id="APP_NAME_0">^1</xliff:g> ta fshijë këtë artikull?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> artikuj po fshihen…</item>
+ <item quantity="one">Një artikull po fshihet…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> nuk mund t\'i përpunojë skedarët e medias"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Përpunimi i medias u anulua"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Gabim i përpunimit të medias"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Përpunimi i medias u krye me sukses"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Përpunimi i medias ka filluar"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Media po përpunohet…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Anulo"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Prit"</string>
</resources>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 079f9aa..cfc2aa8 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -50,79 +50,167 @@
<item quantity="few">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> измени <xliff:g id="COUNT">^2</xliff:g> аудио датотеке?</item>
<item quantity="other">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> измени <xliff:g id="COUNT">^2</xliff:g> аудио датотека?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="one">Мења се <xliff:g id="COUNT">^1</xliff:g> аудио фајл…</item>
+ <item quantity="few">Мењају се <xliff:g id="COUNT">^1</xliff:g> аудио фајла…</item>
+ <item quantity="other">Мења се <xliff:g id="COUNT">^1</xliff:g> аудио фајлова…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="one">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> измени <xliff:g id="COUNT">^2</xliff:g> видео?</item>
<item quantity="few">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> измени <xliff:g id="COUNT">^2</xliff:g> видео снимка?</item>
<item quantity="other">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> измени <xliff:g id="COUNT">^2</xliff:g> видео снимака?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="one">Мења се <xliff:g id="COUNT">^1</xliff:g> видео…</item>
+ <item quantity="few">Мењају се <xliff:g id="COUNT">^1</xliff:g> видео снимка…</item>
+ <item quantity="other">Мења се <xliff:g id="COUNT">^1</xliff:g> видео снимака…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="one">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> измени <xliff:g id="COUNT">^2</xliff:g> слику?</item>
<item quantity="few">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> измени <xliff:g id="COUNT">^2</xliff:g> слике?</item>
<item quantity="other">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> измени <xliff:g id="COUNT">^2</xliff:g> слика?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="one">Мења се <xliff:g id="COUNT">^1</xliff:g> слика…</item>
+ <item quantity="few">Мењају се <xliff:g id="COUNT">^1</xliff:g> слике…</item>
+ <item quantity="other">Мења се <xliff:g id="COUNT">^1</xliff:g> слика…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="one">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> измени <xliff:g id="COUNT">^2</xliff:g> ставку?</item>
<item quantity="few">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> измени <xliff:g id="COUNT">^2</xliff:g> ставке?</item>
<item quantity="other">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> измени <xliff:g id="COUNT">^2</xliff:g> ставки?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="one">Мења се <xliff:g id="COUNT">^1</xliff:g> ставка…</item>
+ <item quantity="few">Мењају се <xliff:g id="COUNT">^1</xliff:g> ставке…</item>
+ <item quantity="other">Мења се <xliff:g id="COUNT">^1</xliff:g> ставки…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="one">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> премести <xliff:g id="COUNT">^2</xliff:g> аудио датотеку у отпад?</item>
<item quantity="few">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> премести <xliff:g id="COUNT">^2</xliff:g> аудио датотеке у отпад?</item>
<item quantity="other">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> премести <xliff:g id="COUNT">^2</xliff:g> аудио датотека у отпад?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> аудио фајл се премешта у отпад…</item>
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> аудио фајла се премештају у отпад…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> аудио фајлова се премешта у отпад…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="one">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> премести <xliff:g id="COUNT">^2</xliff:g> видео у отпад?</item>
<item quantity="few">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> премести <xliff:g id="COUNT">^2</xliff:g> видео снимка у отпад?</item>
<item quantity="other">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> премести <xliff:g id="COUNT">^2</xliff:g> видео снимака у отпад?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> видео се премешта у отпад…</item>
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> видео снимка се премештају у отпад…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> видео снимака се премешта у отпад…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="one">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> премести <xliff:g id="COUNT">^2</xliff:g> слику у отпад?</item>
<item quantity="few">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> премести <xliff:g id="COUNT">^2</xliff:g> слике у отпад?</item>
<item quantity="other">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> премести <xliff:g id="COUNT">^2</xliff:g> слика у отпад?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> слика се премешта у отпад…</item>
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> слике се премештају у отпад…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> слика се премешта у отпад…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="one">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> премести <xliff:g id="COUNT">^2</xliff:g> ставку у отпад?</item>
<item quantity="few">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> премести <xliff:g id="COUNT">^2</xliff:g> ставке у отпад?</item>
<item quantity="other">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> премести <xliff:g id="COUNT">^2</xliff:g> ставки у отпад?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ставка се премешта у отпад…</item>
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> ставке се премештају у отпад…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ставки се премешта у отпад…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="one">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> премести <xliff:g id="COUNT">^2</xliff:g> аудио датотеку из отпада?</item>
<item quantity="few">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> премести <xliff:g id="COUNT">^2</xliff:g> аудио датотеке из отпада?</item>
<item quantity="other">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> премести <xliff:g id="COUNT">^2</xliff:g> аудио датотека из отпада?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> аудио фајл се премешта из отпада…</item>
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> аудио фајла се премештају из отпада…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> аудио фајлова се премешта из отпада…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="one">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> премести <xliff:g id="COUNT">^2</xliff:g> видео из отпада?</item>
<item quantity="few">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> премести <xliff:g id="COUNT">^2</xliff:g> видео снимка из отпада?</item>
<item quantity="other">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> премести <xliff:g id="COUNT">^2</xliff:g> видео снимака из отпада?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> видео се премешта из отпада…</item>
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> видео снимка се премештају из отпада…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> видео снимака се премешта из отпада…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="one">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> премести <xliff:g id="COUNT">^2</xliff:g> слику из отпада?</item>
<item quantity="few">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> премести <xliff:g id="COUNT">^2</xliff:g> слике из отпада?</item>
<item quantity="other">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> премести <xliff:g id="COUNT">^2</xliff:g> слика из отпада?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> слика се премешта из отпада…</item>
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> слике се премештају из отпада…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> слика се премешта из отпада…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="one">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> премести <xliff:g id="COUNT">^2</xliff:g> ставку из отпада?</item>
<item quantity="few">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> премести <xliff:g id="COUNT">^2</xliff:g> ставке из отпада?</item>
<item quantity="other">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> премести <xliff:g id="COUNT">^2</xliff:g> ставки из отпада?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="one"><xliff:g id="COUNT">^1</xliff:g> ставка се премешта из отпада…</item>
+ <item quantity="few"><xliff:g id="COUNT">^1</xliff:g> ставке се премештају из отпада…</item>
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ставки се премешта из отпада…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="one">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> избрише <xliff:g id="COUNT">^2</xliff:g> аудио датотеку?</item>
<item quantity="few">Желите ли да дозволите <xliff:g id="APP_NAME_1">^1</xliff:g> избрише <xliff:g id="COUNT">^2</xliff:g> аудио датотеке?</item>
<item quantity="other">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> избрише <xliff:g id="COUNT">^2</xliff:g> аудио датотека?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="one">Брише се <xliff:g id="COUNT">^1</xliff:g> аудио фајл…</item>
+ <item quantity="few">Бришу се <xliff:g id="COUNT">^1</xliff:g> аудио фајла…</item>
+ <item quantity="other">Брише се <xliff:g id="COUNT">^1</xliff:g> аудио фајлова…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="one">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> избрише <xliff:g id="COUNT">^2</xliff:g> видео?</item>
<item quantity="few">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> избрише <xliff:g id="COUNT">^2</xliff:g> видео снимка?</item>
<item quantity="other">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> избрише <xliff:g id="COUNT">^2</xliff:g> видео снимака?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="one">Брише се <xliff:g id="COUNT">^1</xliff:g> видео…</item>
+ <item quantity="few">Бришу се <xliff:g id="COUNT">^1</xliff:g> видео снимка…</item>
+ <item quantity="other">Брише се <xliff:g id="COUNT">^1</xliff:g> видео снимака…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="one">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> избрише <xliff:g id="COUNT">^2</xliff:g> слику?</item>
<item quantity="few">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> избрише <xliff:g id="COUNT">^2</xliff:g> слике?</item>
<item quantity="other">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> избрише <xliff:g id="COUNT">^2</xliff:g> слика?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="one">Брише се <xliff:g id="COUNT">^1</xliff:g> слика…</item>
+ <item quantity="few">Бришу се <xliff:g id="COUNT">^1</xliff:g> слике…</item>
+ <item quantity="other">Брише се <xliff:g id="COUNT">^1</xliff:g> слика…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="one">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> избрише <xliff:g id="COUNT">^2</xliff:g> ставку?</item>
<item quantity="few">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> избрише <xliff:g id="COUNT">^2</xliff:g> ставке?</item>
<item quantity="other">Желите ли да дозволите да <xliff:g id="APP_NAME_1">^1</xliff:g> избрише <xliff:g id="COUNT">^2</xliff:g> ставки?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="one">Брише се <xliff:g id="COUNT">^1</xliff:g> ставка…</item>
+ <item quantity="few">Бришу се <xliff:g id="COUNT">^1</xliff:g> ставке…</item>
+ <item quantity="other">Брише се <xliff:g id="COUNT">^1</xliff:g> ставки…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> не може да обради медијске фајлове"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Обрада медија је отказана"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Грешка при обради медија"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Обрада медија је успела"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Обрада медија је започела"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Обрађују се медији…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Откажи"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Сачекај"</string>
</resources>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index b0b990c..a576b61 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">Vill du tillåta att <xliff:g id="APP_NAME_1">^1</xliff:g> ändrar <xliff:g id="COUNT">^2</xliff:g> ljudfiler?</item>
<item quantity="one">Vill du tillåta att <xliff:g id="APP_NAME_0">^1</xliff:g> ändrar den här ljudfilen?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ljudfiler modifieras …</item>
+ <item quantity="one">Ljudfilen modifieras …</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">Vill du tillåta att <xliff:g id="APP_NAME_1">^1</xliff:g> ändrar <xliff:g id="COUNT">^2</xliff:g> videor?</item>
<item quantity="one">Vill du tillåta att <xliff:g id="APP_NAME_0">^1</xliff:g> ändrar den här videon?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> videor modifieras …</item>
+ <item quantity="one">Videon modifieras …</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">Vill du tillåta att <xliff:g id="APP_NAME_1">^1</xliff:g> ändrar <xliff:g id="COUNT">^2</xliff:g> foton?</item>
<item quantity="one">Vill du tillåta att <xliff:g id="APP_NAME_0">^1</xliff:g> ändrar det här fotot?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> foton modifieras …</item>
+ <item quantity="one">Fotot modifieras …</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">Vill du tillåta att <xliff:g id="APP_NAME_1">^1</xliff:g> ändrar <xliff:g id="COUNT">^2</xliff:g> objekt?</item>
<item quantity="one">Vill du tillåta att <xliff:g id="APP_NAME_0">^1</xliff:g> ändrar det här objektet?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> objekt modifieras …</item>
+ <item quantity="one">Objektet modifieras …</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">Vill du tillåta att <xliff:g id="APP_NAME_1">^1</xliff:g> flyttar <xliff:g id="COUNT">^2</xliff:g> ljudfiler till papperskorgen?</item>
<item quantity="one">Vill du tillåta att <xliff:g id="APP_NAME_0">^1</xliff:g> flyttar den här ljudfilen till papperskorgen?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ljudfiler flyttas till papperskorgen …</item>
+ <item quantity="one">Ljudfilen flyttas till papperskorgen …</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">Vill du tillåta att <xliff:g id="APP_NAME_1">^1</xliff:g> flyttar <xliff:g id="COUNT">^2</xliff:g> videor till papperskorgen?</item>
<item quantity="one">Vill du tillåta att <xliff:g id="APP_NAME_0">^1</xliff:g> flyttar den här videon till papperskorgen?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> videor flyttas till papperskorgen …</item>
+ <item quantity="one">Videon flyttas till papperskorgen …</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">Vill du tillåta att <xliff:g id="APP_NAME_1">^1</xliff:g> flyttar <xliff:g id="COUNT">^2</xliff:g> foton till papperskorgen?</item>
<item quantity="one">Vill du tillåta att <xliff:g id="APP_NAME_0">^1</xliff:g> flyttar det här fotot till papperskorgen?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> foton flyttas till papperskorgen …</item>
+ <item quantity="one">Fotot flyttas till papperskorgen …</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">Vill du tillåta att <xliff:g id="APP_NAME_1">^1</xliff:g> flyttar <xliff:g id="COUNT">^2</xliff:g> objekt till papperskorgen?</item>
<item quantity="one">Vill du tillåta att <xliff:g id="APP_NAME_0">^1</xliff:g> flyttar det här objektet till papperskorgen?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> objekt flyttas till papperskorgen …</item>
+ <item quantity="one">Objektet flyttas till papperskorgen …</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">Vill du tillåta att <xliff:g id="APP_NAME_1">^1</xliff:g> flyttar <xliff:g id="COUNT">^2</xliff:g> ljudfiler från papperskorgen?</item>
<item quantity="one">Vill du tillåta att <xliff:g id="APP_NAME_0">^1</xliff:g> flyttar den här ljudfilen från papperskorgen?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ljudfiler flyttas från papperskorgen …</item>
+ <item quantity="one">Ljudfilen flyttas från papperskorgen …</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">Vill du tillåta att <xliff:g id="APP_NAME_1">^1</xliff:g> flyttar <xliff:g id="COUNT">^2</xliff:g> videor från papperskorgen?</item>
<item quantity="one">Vill du tillåta att <xliff:g id="APP_NAME_0">^1</xliff:g> flyttar den här videon från papperskorgen?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> videor flyttas från papperskorgen …</item>
+ <item quantity="one">Videon flyttas från papperskorgen …</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">Vill du tillåta att <xliff:g id="APP_NAME_1">^1</xliff:g> flyttar <xliff:g id="COUNT">^2</xliff:g> foton från papperskorgen?</item>
<item quantity="one">Vill du tillåta att <xliff:g id="APP_NAME_0">^1</xliff:g> flyttar det här fotot från papperskorgen?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> foton flyttas från papperskorgen …</item>
+ <item quantity="one">Fotot flyttas från papperskorgen …</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">Vill du tillåta att <xliff:g id="APP_NAME_1">^1</xliff:g> flyttar <xliff:g id="COUNT">^2</xliff:g> objekt från papperskorgen?</item>
<item quantity="one">Vill du tillåta att <xliff:g id="APP_NAME_0">^1</xliff:g> flyttar det här objektet från papperskorgen?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> objekt flyttas från papperskorgen …</item>
+ <item quantity="one">Objektet flyttas från papperskorgen …</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">Vill du tillåta att <xliff:g id="APP_NAME_1">^1</xliff:g> raderar <xliff:g id="COUNT">^2</xliff:g> ljudfiler?</item>
<item quantity="one">Vill du tillåta att <xliff:g id="APP_NAME_0">^1</xliff:g> raderar den här ljudfilen?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ljudfiler raderas …</item>
+ <item quantity="one">Ljudfilen raderas …</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">Vill du tillåta att <xliff:g id="APP_NAME_1">^1</xliff:g> raderar <xliff:g id="COUNT">^2</xliff:g> videor?</item>
<item quantity="one">Vill du tillåta att <xliff:g id="APP_NAME_0">^1</xliff:g> raderar den här videon?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> videor raderas …</item>
+ <item quantity="one">Videon raderas …</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">Vill du tillåta att <xliff:g id="APP_NAME_1">^1</xliff:g> raderar <xliff:g id="COUNT">^2</xliff:g> foton?</item>
<item quantity="one">Vill du tillåta att <xliff:g id="APP_NAME_0">^1</xliff:g> raderar det här fotot?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> foton raderas …</item>
+ <item quantity="one">Fotot raderas …</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">Vill du tillåta att <xliff:g id="APP_NAME_1">^1</xliff:g> raderar <xliff:g id="COUNT">^2</xliff:g> objekt?</item>
<item quantity="one">Vill du tillåta att <xliff:g id="APP_NAME_0">^1</xliff:g> raderar det här objektet?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> objekt raderas …</item>
+ <item quantity="one">Objektet raderas …</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> kan inte behandla mediefiler"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Mediebearbetningen har avbrutits"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Fel vid mediebearbetning"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Mediebearbetningen har slutförts"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Mediebearbetningen har startats"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Bearbetar media …"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Avbryt"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Vänta"</string>
</resources>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 4917e30..1357d44 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">Ungependa kuruhusu <xliff:g id="APP_NAME_1">^1</xliff:g> ibadilishe faili <xliff:g id="COUNT">^2</xliff:g> za sauti?</item>
<item quantity="one">Ungependa kuruhusu <xliff:g id="APP_NAME_0">^1</xliff:g> ibadilishe faili hii ya sauti?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other">Inarekebisha faili <xliff:g id="COUNT">^1</xliff:g> za sauti…</item>
+ <item quantity="one">Inarekebisha faili ya sauti…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">Ungependa kuruhusu <xliff:g id="APP_NAME_1">^1</xliff:g> ibadilishe video <xliff:g id="COUNT">^2</xliff:g>?</item>
<item quantity="one">Ungependa kuruhusu <xliff:g id="APP_NAME_0">^1</xliff:g> ibadilishe video hii?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other">Inarekebisha video <xliff:g id="COUNT">^1</xliff:g>…</item>
+ <item quantity="one">Inarekebisha video…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">Ungependa kuruhusu <xliff:g id="APP_NAME_1">^1</xliff:g> ibadilishe picha <xliff:g id="COUNT">^2</xliff:g>?</item>
<item quantity="one">Ungependa kuruhusu <xliff:g id="APP_NAME_0">^1</xliff:g> ibadilishe picha hii?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other">Inarekebisha picha <xliff:g id="COUNT">^1</xliff:g>…</item>
+ <item quantity="one">Inarekebisha picha…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">Ungependa kuruhusu <xliff:g id="APP_NAME_1">^1</xliff:g> ibadilishe vipengee <xliff:g id="COUNT">^2</xliff:g>?</item>
<item quantity="one">Ungependa kuruhusu <xliff:g id="APP_NAME_0">^1</xliff:g> ibadilishe kipengee hiki?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other">Inarekebisha vipengee <xliff:g id="COUNT">^1</xliff:g>…</item>
+ <item quantity="one">Inarekebisha kipengee…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">Ungependa kuruhusu <xliff:g id="APP_NAME_1">^1</xliff:g> ihamishie faili <xliff:g id="COUNT">^2</xliff:g> za sauti kwenye tupio?</item>
<item quantity="one">Ungependa kuruhusu <xliff:g id="APP_NAME_0">^1</xliff:g> ihamishie faili hii ya sauti kwenye tupio?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other">Inahamishia faili <xliff:g id="COUNT">^1</xliff:g> za sauti kwenye tupio…</item>
+ <item quantity="one">Inahamishia faili ya sauti kwenye tupio…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">Ungependa kuruhusu <xliff:g id="APP_NAME_1">^1</xliff:g> ihamishie video <xliff:g id="COUNT">^2</xliff:g> kwenye tupio?</item>
<item quantity="one">Ungependa kuruhusu <xliff:g id="APP_NAME_0">^1</xliff:g> ihamishie video hii kwenye tupio?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other">Inahamishia video <xliff:g id="COUNT">^1</xliff:g> kwenye tupio…</item>
+ <item quantity="one">Inahamishia video kwenye tupio…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">Ungependa kuruhusu <xliff:g id="APP_NAME_1">^1</xliff:g> ihamishie picha <xliff:g id="COUNT">^2</xliff:g> kwenye tupio?</item>
<item quantity="one">Ungependa kuruhusu <xliff:g id="APP_NAME_0">^1</xliff:g> ihamishie picha hii kwenye tupio?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other">Inahamishia picha <xliff:g id="COUNT">^1</xliff:g> kwenye tupio…</item>
+ <item quantity="one">Inahamishia picha kwenye tupio…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">Ungependa kuruhusu <xliff:g id="APP_NAME_1">^1</xliff:g> ihamishie vipengee <xliff:g id="COUNT">^2</xliff:g> kwenye tupio?</item>
<item quantity="one">Ungependa kuruhusu <xliff:g id="APP_NAME_0">^1</xliff:g> ihamishie kipengee hiki kwenye tupio?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other">Inahamishia vipengee <xliff:g id="COUNT">^1</xliff:g> kwenye tupio…</item>
+ <item quantity="one">Inahamishia kipengee kwenye tupio…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">Ungependa kuruhusu <xliff:g id="APP_NAME_1">^1</xliff:g> iondoe faili <xliff:g id="COUNT">^2</xliff:g> za sauti kwenye tupio?</item>
<item quantity="one">Ungependa kuruhusu <xliff:g id="APP_NAME_0">^1</xliff:g> iondoe faili hii ya sauti kwenye tupio?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other">Inahamishia faili <xliff:g id="COUNT">^1</xliff:g> za sauti kwenye tupio…</item>
+ <item quantity="one">Inahamishia faili ya sauti kwenye tupio…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">Ungependa kuruhusu <xliff:g id="APP_NAME_1">^1</xliff:g> iondoe video <xliff:g id="COUNT">^2</xliff:g> kwenye tupio?</item>
<item quantity="one">Ungependa kuruhusu <xliff:g id="APP_NAME_0">^1</xliff:g> iondoe video hii kwenye tupio?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other">Inaondoa video <xliff:g id="COUNT">^1</xliff:g> kwenye tupio…</item>
+ <item quantity="one">Inaondoa video kwenye tupio…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">Ungependa kuruhusu <xliff:g id="APP_NAME_1">^1</xliff:g> iondoe picha <xliff:g id="COUNT">^2</xliff:g> kwenye tupio?</item>
<item quantity="one">Ungependa kuruhusu <xliff:g id="APP_NAME_0">^1</xliff:g> iondoe picha hii kwenye tupio?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other">Inaondoa picha <xliff:g id="COUNT">^1</xliff:g> kwenye tupio…</item>
+ <item quantity="one">Inaondoa picha kwenye tupio…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">Ungependa kuruhusu <xliff:g id="APP_NAME_1">^1</xliff:g> iondoe vipengee <xliff:g id="COUNT">^2</xliff:g> kwenye tupio?</item>
<item quantity="one">Ungependa kuruhusu <xliff:g id="APP_NAME_0">^1</xliff:g> iondoe kipengee hiki kwenye tupio?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other">Inaondoa vipengee <xliff:g id="COUNT">^1</xliff:g> kwenye tupio…</item>
+ <item quantity="one">Inaondoa kipengee kwenye tupio…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">Ungependa kuruhusu <xliff:g id="APP_NAME_1">^1</xliff:g> ifute faili <xliff:g id="COUNT">^2</xliff:g> za sauti?</item>
<item quantity="one">Ungependa kuruhusu <xliff:g id="APP_NAME_0">^1</xliff:g> ifute faili hii ya sauti?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other">Inafuta faili <xliff:g id="COUNT">^1</xliff:g> za sauti…</item>
+ <item quantity="one">Inafuta faili ya sauti…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">Ungependa kuruhusu <xliff:g id="APP_NAME_1">^1</xliff:g> ifute video <xliff:g id="COUNT">^2</xliff:g>?</item>
<item quantity="one">Ungependa kuruhusu <xliff:g id="APP_NAME_0">^1</xliff:g> ifute video hii?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other">Inafuta video <xliff:g id="COUNT">^1</xliff:g>…</item>
+ <item quantity="one">Inafuta video…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">Ungependa kuruhusu <xliff:g id="APP_NAME_1">^1</xliff:g> ifute picha <xliff:g id="COUNT">^2</xliff:g>?</item>
<item quantity="one">Ungependa kuruhusu <xliff:g id="APP_NAME_0">^1</xliff:g> ifute picha hii?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other">Inafuta picha <xliff:g id="COUNT">^1</xliff:g>…</item>
+ <item quantity="one">Inafuta picha…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">Ungependa kuruhusu <xliff:g id="APP_NAME_1">^1</xliff:g> ifute vipengee <xliff:g id="COUNT">^2</xliff:g>?</item>
<item quantity="one">Ungependa kuruhusu <xliff:g id="APP_NAME_0">^1</xliff:g> ifute kipengee hiki?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other">Inafuta vipengee <xliff:g id="COUNT">^1</xliff:g>…</item>
+ <item quantity="one">Inafuta kipengee…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> imeshindwa kuchakata faili za maudhui"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Mchakato wa maudhui umeghairiwa"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Hitilafu ya kuchakata maudhui"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Imemaliza kuchakata maudhui"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Imeanza kuchakata maudhui"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Inachakata maudhui…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Ghairi"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Subiri"</string>
</resources>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index f13588a..e1404f6 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ஆடியோ ஃபைல்களில் மாற்றங்களைச் செய்ய <xliff:g id="APP_NAME_1">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
<item quantity="one">இந்த ஆடியோ ஃபைலில் மாற்றங்களைச் செய்ய <xliff:g id="APP_NAME_0">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ஆடியோ கோப்புகளை மாற்றியமைக்கிறது…</item>
+ <item quantity="one">ஆடியோ கோப்பை மாற்றியமைக்கிறது…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> வீடியோக்களில் மாற்றங்களைச் செய்ய <xliff:g id="APP_NAME_1">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
<item quantity="one">இந்த வீடியோவில் மாற்றங்களைச் செய்ய <xliff:g id="APP_NAME_0">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> வீடியோக்களை மாற்றியமைக்கிறது…</item>
+ <item quantity="one">வீடியோவை மாற்றியமைக்கிறது…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> படங்களில் மாற்றங்களைச் செய்ய <xliff:g id="APP_NAME_1">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
<item quantity="one">இந்தப் படத்தில் மாற்றங்களைச் செய்ய <xliff:g id="APP_NAME_0">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> படங்களை மாற்றியமைக்கிறது…</item>
+ <item quantity="one">படத்தை மாற்றியமைக்கிறது…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ஃபைல்களில் மாற்றங்களைச் செய்ய <xliff:g id="APP_NAME_1">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
<item quantity="one">இந்த ஃபைலில் மாற்றங்களைச் செய்ய <xliff:g id="APP_NAME_0">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ஆவணங்களை மாற்றியமைக்கிறது…</item>
+ <item quantity="one">ஆவணத்தை மாற்றியமைக்கிறது…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ஆடியோ ஃபைல்களை நீக்கியவற்றிற்கு நகர்த்த <xliff:g id="APP_NAME_1">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
<item quantity="one">இந்த ஆடியோ ஃபைலை நீக்கியவற்றிற்கு நகர்த்த <xliff:g id="APP_NAME_0">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ஆடியோ கோப்புகளை ‘நீக்கியவை’ கோப்புறைக்கு நகர்த்துகிறது…</item>
+ <item quantity="one">ஆடியோ கோப்பை ‘நீக்கியவை’ கோப்புறைக்கு நகர்த்துகிறது…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> வீடியோக்களை நீக்கியவற்றிற்கு நகர்த்த <xliff:g id="APP_NAME_1">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
<item quantity="one">இந்த வீடியோவை நீக்கியவற்றிற்கு நகர்த்த <xliff:g id="APP_NAME_0">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> வீடியோக்களை ‘நீக்கியவை’ கோப்புறைக்கு நகர்த்துகிறது…</item>
+ <item quantity="one">வீடியோவை ‘நீக்கியவை’ கோப்புறைக்கு நகர்த்துகிறது…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> படங்களை நீக்கியவற்றிற்கு நகர்த்த <xliff:g id="APP_NAME_1">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
<item quantity="one">இந்தப் படத்தை நீக்கியவற்றிற்கு நகர்த்த <xliff:g id="APP_NAME_0">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> படங்களை ‘நீக்கியவை’ கோப்புறைக்கு நகர்த்துகிறது…</item>
+ <item quantity="one">படத்தை ‘நீக்கியவை’ கோப்புறைக்கு நகர்த்துகிறது…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ஃபைல்களை நீக்கியவற்றிற்கு நகர்த்த <xliff:g id="APP_NAME_1">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
<item quantity="one">இந்த ஃபைலை நீக்கியவற்றிற்கு நகர்த்த <xliff:g id="APP_NAME_0">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ஆவணங்களை ‘நீக்கியவை’ கோப்புறைக்கு நகர்த்துகிறது…</item>
+ <item quantity="one">ஆவணத்தை ‘நீக்கியவை’ கோப்புறைக்கு நகர்த்துகிறது…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ஆடியோ ஃபைல்களை நீக்கியவற்றில் இருந்து நகர்த்த <xliff:g id="APP_NAME_1">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
<item quantity="one">இந்த ஆடியோ ஃபைலை நீக்கியவற்றில் இருந்து நகர்த்த <xliff:g id="APP_NAME_0">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ஆடியோ கோப்புகளை ‘நீக்கியவை’ கோப்புறையிலிருந்து நகர்த்துகிறது…</item>
+ <item quantity="one">ஆடியோ கோப்பை ‘நீக்கியவை’ கோப்புறையிலிருந்து நகர்த்துகிறது…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> வீடியோக்களை நீக்கியவற்றில் இருந்து நகர்த்த <xliff:g id="APP_NAME_1">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
<item quantity="one">இந்த வீடியோவை நீக்கியவற்றில் இருந்து நகர்த்த <xliff:g id="APP_NAME_0">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> வீடியோக்களை ‘நீக்கியவை’ கோப்புறையிலிருந்து நகர்த்துகிறது…</item>
+ <item quantity="one">வீடியோவை ‘நீக்கியவை’ கோப்புறையிலிருந்து நகர்த்துகிறது…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> படங்களை நீக்கியவற்றில் இருந்து நகர்த்த <xliff:g id="APP_NAME_1">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
<item quantity="one">இந்தப் படத்தை நீக்கியவற்றில் இருந்து நகர்த்த <xliff:g id="APP_NAME_0">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> படங்களை ‘நீக்கியவை’ கோப்புறையிலிருந்து நகர்த்துகிறது…</item>
+ <item quantity="one">படத்தை ‘நீக்கியவை’ கோப்புறையிலிருந்து நகர்த்துகிறது…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ஃபைல்களை நீக்கியவற்றில் இருந்து நகர்த்த <xliff:g id="APP_NAME_1">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
<item quantity="one">இந்த ஃபைலை நீக்கியவற்றில் இருந்து நகர்த்த <xliff:g id="APP_NAME_0">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ஆவணங்களை ‘நீக்கியவை’ கோப்புறையிலிருந்து நகர்த்துகிறது…</item>
+ <item quantity="one">ஆவணத்தை ‘நீக்கியவை’ கோப்புறையிலிருந்து நகர்த்துகிறது…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ஆடியோ ஃபைல்களை நீக்க <xliff:g id="APP_NAME_1">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
<item quantity="one">இந்த ஆடியோ ஃபைலை நீக்க <xliff:g id="APP_NAME_0">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ஆடியோ கோப்புகளை நீக்குகிறது…</item>
+ <item quantity="one">ஆடியோ கோப்பை நீக்குகிறது…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> வீடியோக்களை நீக்க <xliff:g id="APP_NAME_1">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
<item quantity="one">இந்த வீடியோவை நீக்க <xliff:g id="APP_NAME_0">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> வீடியோக்களை நீக்குகிறது…</item>
+ <item quantity="one">வீடியோவை நீக்குகிறது…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> படங்களை நீக்க <xliff:g id="APP_NAME_1">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
<item quantity="one">இந்தப் படத்தை நீக்க <xliff:g id="APP_NAME_0">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> படங்களை நீக்குகிறது…</item>
+ <item quantity="one">படத்தை நீக்குகிறது…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ஃபைல்களை நீக்க <xliff:g id="APP_NAME_1">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
<item quantity="one">இந்த ஃபைலை நீக்க <xliff:g id="APP_NAME_0">^1</xliff:g> ஆப்ஸை அனுமதிக்கவா?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ஆவணங்களை நீக்குகிறது…</item>
+ <item quantity="one">ஆவணத்தை நீக்குகிறது…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"மீடியா கோப்புகளை <xliff:g id="APP_NAME">%s</xliff:g> ஆப்ஸால் செயலாக்க முடியவில்லை"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"மீடியா செயலாக்கம் ரத்துசெய்யப்பட்டது"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"மீடியா செயலாக்கத்தில் பிழை"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"மீடியா செயலாக்கம் நிறைவடைந்தது"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"மீடியா செயலாக்கம் தொடங்கியது"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"மீடியாவைச் செயலாக்குகிறது…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"ரத்துசெய்"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"காத்திருங்கள்"</string>
</resources>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 30c0faa..2b14c3e 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ఆడియో ఫైల్లను సవరించడానికి <xliff:g id="APP_NAME_1">^1</xliff:g>ను అనుమతించాలా?</item>
<item quantity="one">ఈ ఆడియో ఫైల్ను సవరించడానికి <xliff:g id="APP_NAME_0">^1</xliff:g>ను అనుమతించాలా?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ఆడియో ఫైల్లను సవరిస్తోంది…</item>
+ <item quantity="one">ఆడియో ఫైల్ను సవరిస్తోంది…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> వీడియోలను సవరించడానికి <xliff:g id="APP_NAME_1">^1</xliff:g>ను అనుమతించాలా?</item>
<item quantity="one">ఈ వీడియోను సవరించడానికి <xliff:g id="APP_NAME_0">^1</xliff:g>ను అనుమతించాలా?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> వీడియోలను సవరిస్తోంది…</item>
+ <item quantity="one">వీడియోను సవరిస్తోంది…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ఫోటోలను సవరించడానికి <xliff:g id="APP_NAME_1">^1</xliff:g>ను అనుమతించాలా?</item>
<item quantity="one">ఈ ఫోటోను సవరించడానికి <xliff:g id="APP_NAME_0">^1</xliff:g>ను అనుమతించాలా?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ఫోటోలను సవరిస్తోంది…</item>
+ <item quantity="one">ఫోటోను సవరిస్తోంది…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ఐటెమ్లను సవరించడానికి <xliff:g id="APP_NAME_1">^1</xliff:g>ను అనుమతించాలా?</item>
<item quantity="one">ఈ ఐటెమ్ను సవరించడానికి <xliff:g id="APP_NAME_0">^1</xliff:g>ను అనుమతించాలా?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ఐటెమ్లను సవరిస్తోంది…</item>
+ <item quantity="one">ఐటెమ్ను సవరిస్తోంది…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ఆడియో ఫైల్లను ట్రాష్కు తరలించడానికి <xliff:g id="APP_NAME_1">^1</xliff:g>ను అనుమతించాలా?</item>
<item quantity="one">ఈ ఆడియో ఫైల్ను ట్రాష్కు తరలించడానికి <xliff:g id="APP_NAME_0">^1</xliff:g>ను అనుమతించాలా?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ఆడియో ఫైల్లను ట్రాష్కు తరలిస్తోంది…</item>
+ <item quantity="one">ఆడియో ఫైల్ను ట్రాష్కు తరలిస్తోంది…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> వీడియోలను ట్రాష్కు తరలించడానికి <xliff:g id="APP_NAME_1">^1</xliff:g>ను అనుమతించాలా?</item>
<item quantity="one">ఈ వీడియోను ట్రాష్కు తరలించడానికి <xliff:g id="APP_NAME_0">^1</xliff:g>ను అనుమతించాలా?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> వీడియోలను ట్రాష్కు తరలిస్తోంది…</item>
+ <item quantity="one">వీడియోను ట్రాష్కు తరలిస్తోంది…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ఫోటోలను ట్రాష్కు తరలించడానికి <xliff:g id="APP_NAME_1">^1</xliff:g>ను అనుమతించాలా?</item>
<item quantity="one">ఈ ఫోటోను ట్రాష్కు తరలించడానికి <xliff:g id="APP_NAME_0">^1</xliff:g>ను అనుమతించాలా?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ఫోటోలను ట్రాష్కు తరలిస్తోంది…</item>
+ <item quantity="one">ఫోటోను ట్రాష్కు తరలిస్తోంది…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ఐటెమ్లను ట్రాష్కు తరలించడానికి <xliff:g id="APP_NAME_1">^1</xliff:g>ను అనుమతించాలా?</item>
<item quantity="one">ఈ ఐటెమ్ను ట్రాష్కు తరలించడానికి <xliff:g id="APP_NAME_0">^1</xliff:g>ను అనుమతించాలా?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ఐటెమ్లను ట్రాష్కు తరలిస్తోంది…</item>
+ <item quantity="one">ఐటెమ్ను ట్రాష్కు తరలిస్తోంది…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ఆడియో ఫైల్లను ట్రాష్ నుండి బయటకు తీయడానికి <xliff:g id="APP_NAME_1">^1</xliff:g>ను అనుమతించాలా?</item>
<item quantity="one">ఈ ఆడియో ఫైల్ను ట్రాష్ నుండి బయటకు తీయడానికి <xliff:g id="APP_NAME_0">^1</xliff:g>ను అనుమతించాలా?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ఆడియో ఫైల్లను ట్రాష్ నుండి బయటకు తరలిస్తోంది…</item>
+ <item quantity="one">ఆడియో ఫైల్ను ట్రాష్ నుండి బయటకు తరలిస్తోంది…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> వీడియోలను ట్రాష్ నుండి బయటకు తీయడానికి <xliff:g id="APP_NAME_1">^1</xliff:g>ను అనుమతించాలా?</item>
<item quantity="one">ఈ వీడియోను ట్రాష్ నుండి బయటకు తీయడానికి <xliff:g id="APP_NAME_0">^1</xliff:g>ను అనుమతించాలా?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> వీడియోలను ట్రాష్ నుండి బయటకు తరలిస్తోంది…</item>
+ <item quantity="one">వీడియోను ట్రాష్ నుండి బయటకు తరలిస్తోంది…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ఫోటోలను ట్రాష్ నుండి బయటకు తీయడానికి <xliff:g id="APP_NAME_1">^1</xliff:g>ను అనుమతించాలా?</item>
<item quantity="one">ఈ ఫోటోను ట్రాష్ నుండి బయటకు తీయడానికి <xliff:g id="APP_NAME_0">^1</xliff:g>ను అనుమతించాలా?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ఫోటోలను ట్రాష్ నుండి బయటకు తరలిస్తోంది…</item>
+ <item quantity="one">ఫోటోను ట్రాష్ నుండి బయటకు తరలిస్తోంది…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ఐటెమ్లను ట్రాష్ నుండి బయటకు తీయడానికి <xliff:g id="APP_NAME_1">^1</xliff:g>ను అనుమతించాలా?</item>
<item quantity="one">ఈ ఐటెమ్ను ట్రాష్ నుండి బయటకు తీయడానికి <xliff:g id="APP_NAME_0">^1</xliff:g>ను అనుమతించాలా?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ఐటెమ్లను ట్రాష్ నుండి బయటకు తరలిస్తోంది…</item>
+ <item quantity="one">ఐటెమ్ను ట్రాష్ నుండి బయటకు తరలిస్తోంది…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ఆడియో ఫైల్లను తొలగించడానికి <xliff:g id="APP_NAME_1">^1</xliff:g>ను అనుమతించాలా?</item>
<item quantity="one">ఈ ఆడియో ఫైల్ను తొలగించడానికి <xliff:g id="APP_NAME_0">^1</xliff:g>ను అనుమతించాలా?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g>ఆడియో ఫైల్లను తొలగిస్తోంది…</item>
+ <item quantity="one">ఆడియో ఫైల్ను తొలగిస్తోంది…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> వీడియోలను తొలగించడానికి <xliff:g id="APP_NAME_1">^1</xliff:g>ను అనుమతించాలా?</item>
<item quantity="one">ఈ వీడియోను తొలగించడానికి <xliff:g id="APP_NAME_0">^1</xliff:g>ను అనుమతించాలా?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> వీడియోలను తొలగిస్తోంది…</item>
+ <item quantity="one">వీడియోను తొలగిస్తోంది…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ఫోటోలను తొలగించడానికి <xliff:g id="APP_NAME_1">^1</xliff:g>ను అనుమతించాలా?</item>
<item quantity="one">ఈ ఫోటోను తొలగించడానికి <xliff:g id="APP_NAME_0">^1</xliff:g>ను అనుమతించాలా?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ఫోటోలను తొలగిస్తోంది…</item>
+ <item quantity="one">ఫోటోను తొలగిస్తోంది…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other"><xliff:g id="COUNT">^2</xliff:g> ఐటెమ్లను తొలగించడానికి <xliff:g id="APP_NAME_1">^1</xliff:g>ను అనుమతించాలా?</item>
<item quantity="one">ఈ ఐటెమ్ను తొలగించడానికి <xliff:g id="APP_NAME_0">^1</xliff:g>ను అనుమతించాలా?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ఐటెమ్లను తొలగిస్తోంది…</item>
+ <item quantity="one">ఐటెమ్ను తొలగిస్తోంది…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> మీడియా ఫైల్లను ప్రాసెస్ చేయదు"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"మీడియా ప్రాసెసింగ్ రద్దు చేయబడింది"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"మీడియా ప్రాసెసింగ్లో ఎర్రర్ ఏర్పడింది"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"మీడియా ప్రాసెసింగ్ విజయవంతమైంది"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"మీడియా ప్రాసెసింగ్ ప్రారంభమైంది"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"మీడియాను ప్రాసెస్ చేస్తోంది…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"రద్దు చేయి"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"వేచి ఉండు"</string>
</resources>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index db76bee..da8604c 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">อนุญาตให้ <xliff:g id="APP_NAME_1">^1</xliff:g> แก้ไขไฟล์เสียง <xliff:g id="COUNT">^2</xliff:g> ไฟล์ไหม</item>
<item quantity="one">อนุญาตให้ <xliff:g id="APP_NAME_0">^1</xliff:g> แก้ไขไฟล์เสียงนี้ไหม</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other">กำลังแก้ไขไฟล์เสียง <xliff:g id="COUNT">^1</xliff:g> ไฟล์…</item>
+ <item quantity="one">กำลังแก้ไขไฟล์เสียง…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">อนุญาตให้ <xliff:g id="APP_NAME_1">^1</xliff:g> แก้ไขวิดีโอ <xliff:g id="COUNT">^2</xliff:g> รายการไหม</item>
<item quantity="one">อนุญาตให้ <xliff:g id="APP_NAME_0">^1</xliff:g> แก้ไขวิดีโอนี้ไหม</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other">กำลังแก้ไขวิดีโอ <xliff:g id="COUNT">^1</xliff:g> รายการ…</item>
+ <item quantity="one">กำลังแก้ไขวิดีโอ…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">อนุญาตให้ <xliff:g id="APP_NAME_1">^1</xliff:g> แก้ไขรูปภาพ <xliff:g id="COUNT">^2</xliff:g> รูปไหม</item>
<item quantity="one">อนุญาตให้ <xliff:g id="APP_NAME_0">^1</xliff:g> แก้ไขรูปภาพนี้ไหม</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other">กำลังแก้ไขรูปภาพ <xliff:g id="COUNT">^1</xliff:g> รูป…</item>
+ <item quantity="one">กำลังแก้ไขรูปภาพ…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">อนุญาตให้ <xliff:g id="APP_NAME_1">^1</xliff:g> แก้ไข <xliff:g id="COUNT">^2</xliff:g> รายการไหม</item>
<item quantity="one">อนุญาตให้ <xliff:g id="APP_NAME_0">^1</xliff:g> แก้ไขรายการนี้ไหม</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other">กำลังแก้ไข <xliff:g id="COUNT">^1</xliff:g> รายการ…</item>
+ <item quantity="one">กำลังแก้ไขรายการ…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">อนุญาตให้ <xliff:g id="APP_NAME_1">^1</xliff:g> ย้ายไฟล์เสียง <xliff:g id="COUNT">^2</xliff:g> ไฟล์ไปที่ถังขยะไหม</item>
<item quantity="one">อนุญาตให้ <xliff:g id="APP_NAME_0">^1</xliff:g> ย้ายไฟล์เสียงนี้ไปที่ถังขยะไหม</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other">กำลังย้ายไฟล์เสียง <xliff:g id="COUNT">^1</xliff:g> ไฟล์ไปที่ถังขยะ…</item>
+ <item quantity="one">กำลังย้ายไฟล์เสียงไปที่ถังขยะ…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">อนุญาตให้ <xliff:g id="APP_NAME_1">^1</xliff:g> ย้ายวิดีโอ <xliff:g id="COUNT">^2</xliff:g> รายการไปที่ถังขยะไหม</item>
<item quantity="one">อนุญาตให้ <xliff:g id="APP_NAME_0">^1</xliff:g> ย้ายวิดีโอนี้ไปที่ถังขยะไหม</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other">กำลังย้ายวิดีโอ <xliff:g id="COUNT">^1</xliff:g> รายการไปที่ถังขยะ…</item>
+ <item quantity="one">กำลังย้ายวิดีโอไปที่ถังขยะ…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">อนุญาตให้ <xliff:g id="APP_NAME_1">^1</xliff:g> ย้ายรูปภาพ <xliff:g id="COUNT">^2</xliff:g> รูปไปที่ถังขยะไหม</item>
<item quantity="one">อนุญาตให้ <xliff:g id="APP_NAME_0">^1</xliff:g> ย้ายรูปภาพนี้ไปที่ถังขยะไหม</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other">กำลังย้ายรูปภาพ <xliff:g id="COUNT">^1</xliff:g> รูปไปที่ถังขยะ…</item>
+ <item quantity="one">กำลังย้ายรูปภาพไปที่ถังขยะ…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">อนุญาตให้ <xliff:g id="APP_NAME_1">^1</xliff:g> ย้าย <xliff:g id="COUNT">^2</xliff:g> รายการไปที่ถังขยะไหม</item>
<item quantity="one">อนุญาตให้ <xliff:g id="APP_NAME_0">^1</xliff:g> ย้ายรายการนี้ไปที่ถังขยะไหม</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other">กำลังย้าย <xliff:g id="COUNT">^1</xliff:g> รายการไปที่ถังขยะ…</item>
+ <item quantity="one">กำลังย้ายรายการไปที่ถังขยะ…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">อนุญาตให้ <xliff:g id="APP_NAME_1">^1</xliff:g> ย้ายไฟล์เสียง <xliff:g id="COUNT">^2</xliff:g> ไฟล์ออกจากถังขยะไหม</item>
<item quantity="one">อนุญาตให้ <xliff:g id="APP_NAME_0">^1</xliff:g> ย้ายไฟล์เสียงนี้ออกจากถังขยะไหม</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other">กำลังย้ายไฟล์เสียง <xliff:g id="COUNT">^1</xliff:g> ไฟล์ออกจากถังขยะ…</item>
+ <item quantity="one">กำลังย้ายไฟล์เสียงออกจากถังขยะ…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">อนุญาตให้ <xliff:g id="APP_NAME_1">^1</xliff:g> ย้ายวิดีโอ <xliff:g id="COUNT">^2</xliff:g> รายการออกจากถังขยะไหม</item>
<item quantity="one">อนุญาตให้ <xliff:g id="APP_NAME_0">^1</xliff:g> ย้ายวิดีโอนี้ออกจากถังขยะไหม</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other">กำลังย้ายวิดีโอ <xliff:g id="COUNT">^1</xliff:g> รายการออกจากถังขยะ…</item>
+ <item quantity="one">กำลังย้ายวิดีโอออกจากถังขยะ…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">อนุญาตให้ <xliff:g id="APP_NAME_1">^1</xliff:g> ย้ายรูปภาพ <xliff:g id="COUNT">^2</xliff:g> รูปออกจากถังขยะไหม</item>
<item quantity="one">อนุญาตให้ <xliff:g id="APP_NAME_0">^1</xliff:g> ย้ายรูปภาพนี้ออกจากถังขยะไหม</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other">กำลังย้ายรูปภาพ <xliff:g id="COUNT">^1</xliff:g> รูปออกจากถังขยะ…</item>
+ <item quantity="one">กำลังย้ายรูปภาพออกจากถังขยะ…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">อนุญาตให้ <xliff:g id="APP_NAME_1">^1</xliff:g> ย้าย <xliff:g id="COUNT">^2</xliff:g> รายการออกจากถังขยะไหม</item>
<item quantity="one">อนุญาตให้ <xliff:g id="APP_NAME_0">^1</xliff:g> ย้ายรายการนี้ออกจากถังขยะไหม</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other">กำลังย้าย <xliff:g id="COUNT">^1</xliff:g> รายการออกจากถังขยะ…</item>
+ <item quantity="one">กำลังย้ายรายการออกจากถังขยะ…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">อนุญาตให้ <xliff:g id="APP_NAME_1">^1</xliff:g> ลบไฟล์เสียง <xliff:g id="COUNT">^2</xliff:g> ไฟล์ไหม</item>
<item quantity="one">อนุญาตให้ <xliff:g id="APP_NAME_0">^1</xliff:g> ลบไฟล์เสียงนี้ไหม</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other">กำลังลบไฟล์เสียง <xliff:g id="COUNT">^1</xliff:g> ไฟล์…</item>
+ <item quantity="one">กำลังลบไฟล์เสียง…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">อนุญาตให้ <xliff:g id="APP_NAME_1">^1</xliff:g> ลบวิดีโอ <xliff:g id="COUNT">^2</xliff:g> รายการไหม</item>
<item quantity="one">อนุญาตให้ <xliff:g id="APP_NAME_0">^1</xliff:g> ลบวิดีโอนี้ไหม</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other">กำลังลบวิดีโอ <xliff:g id="COUNT">^1</xliff:g> รายการ…</item>
+ <item quantity="one">กำลังลบวิดีโอ…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">อนุญาตให้ <xliff:g id="APP_NAME_1">^1</xliff:g> ลบรูปภาพ <xliff:g id="COUNT">^2</xliff:g> รูปไหม</item>
<item quantity="one">อนุญาตให้ <xliff:g id="APP_NAME_0">^1</xliff:g> ลบรูปภาพนี้ไหม</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other">กำลังลบรูปภาพ <xliff:g id="COUNT">^1</xliff:g> รูป…</item>
+ <item quantity="one">กำลังลบรูปภาพ…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">อนุญาตให้ <xliff:g id="APP_NAME_1">^1</xliff:g> ลบ <xliff:g id="COUNT">^2</xliff:g> รายการไหม</item>
<item quantity="one">อนุญาตให้ <xliff:g id="APP_NAME_0">^1</xliff:g> ลบรายการนี้ไหม</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other">กำลังลบ <xliff:g id="COUNT">^1</xliff:g> รายการ…</item>
+ <item quantity="one">กำลังลบรายการ…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g>ประมวลผลไฟล์สื่อไม่ได้"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"ยกเลิกการประมวลผลสื่อแล้ว"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"ข้อผิดพลาดในการประมวลผลสื่อ"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"การประมวลผลสื่อสำเร็จแล้ว"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"เริ่มการประมวลผลสื่อแล้ว"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"กำลังประมวลผลสื่อ…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"ยกเลิก"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"รอ"</string>
</resources>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 79452b3..804e99e 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -47,64 +47,136 @@
<item quantity="one">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na i-modify ang <xliff:g id="COUNT">^2</xliff:g> audio file?</item>
<item quantity="other">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na i-modify ang <xliff:g id="COUNT">^2</xliff:g> na audio file?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="one">Nagbabago ng <xliff:g id="COUNT">^1</xliff:g> audio file…</item>
+ <item quantity="other">Nagbabago ng <xliff:g id="COUNT">^1</xliff:g> na audio file…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="one">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na baguhin ang <xliff:g id="COUNT">^2</xliff:g> video?</item>
<item quantity="other">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na baguhin ang <xliff:g id="COUNT">^2</xliff:g> na video?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="one">Nagbabago ng <xliff:g id="COUNT">^1</xliff:g> video…</item>
+ <item quantity="other">Nagbabago ng <xliff:g id="COUNT">^1</xliff:g> na video…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="one">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na baguhin ang <xliff:g id="COUNT">^2</xliff:g> larawan?</item>
<item quantity="other">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na baguhin ang <xliff:g id="COUNT">^2</xliff:g> na larawan?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="one">Nagbabago ng <xliff:g id="COUNT">^1</xliff:g> larawan…</item>
+ <item quantity="other">Nagbabago ng <xliff:g id="COUNT">^1</xliff:g> na larawan…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="one">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na baguhin ang <xliff:g id="COUNT">^2</xliff:g> item?</item>
<item quantity="other">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na baguhin ang <xliff:g id="COUNT">^2</xliff:g> na item?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="one">Nagbabago ng <xliff:g id="COUNT">^1</xliff:g> item…</item>
+ <item quantity="other">Nagbabago ng <xliff:g id="COUNT">^1</xliff:g> na item…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="one">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na ilipat sa trash ang <xliff:g id="COUNT">^2</xliff:g> audio file?</item>
<item quantity="other">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na ilipat sa trash ang <xliff:g id="COUNT">^2</xliff:g> na audio file?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="one">Naglilipat ng <xliff:g id="COUNT">^1</xliff:g> audio file sa trash…</item>
+ <item quantity="other">Naglilipat ng <xliff:g id="COUNT">^1</xliff:g> na audio file sa trash…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="one">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na ilipat sa trash ang <xliff:g id="COUNT">^2</xliff:g> video?</item>
<item quantity="other">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na ilipat sa trash ang <xliff:g id="COUNT">^2</xliff:g> na video?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="one">Naglilipat ng <xliff:g id="COUNT">^1</xliff:g> video sa trash…</item>
+ <item quantity="other">Naglilipat ng <xliff:g id="COUNT">^1</xliff:g> na video sa trash…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="one">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na ilipat sa trash ang <xliff:g id="COUNT">^2</xliff:g> larawan?</item>
<item quantity="other">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na ilipat sa trash ang <xliff:g id="COUNT">^2</xliff:g> na larawan?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="one">Naglilipat ng <xliff:g id="COUNT">^1</xliff:g> larawan sa trash…</item>
+ <item quantity="other">Naglilipat ng <xliff:g id="COUNT">^1</xliff:g> na larawan sa trash…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="one">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na ilipat sa trash ang <xliff:g id="COUNT">^2</xliff:g> item?</item>
<item quantity="other">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na ilipat sa trash ang <xliff:g id="COUNT">^2</xliff:g> na item?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="one">Naglilipat ng <xliff:g id="COUNT">^1</xliff:g> item sa trash…</item>
+ <item quantity="other">Naglilipat ng <xliff:g id="COUNT">^1</xliff:g> na item sa trash…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="one">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na alisin sa trash ang <xliff:g id="COUNT">^2</xliff:g> audio file?</item>
<item quantity="other">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na alisin sa trash ang <xliff:g id="COUNT">^2</xliff:g> na audio file?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="one">Nag-aalis ng <xliff:g id="COUNT">^1</xliff:g> audio file sa trash…</item>
+ <item quantity="other">Nag-aalis ng <xliff:g id="COUNT">^1</xliff:g> na audio file sa trash…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="one">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na alisin sa trash ang <xliff:g id="COUNT">^2</xliff:g> video?</item>
<item quantity="other">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na alisin sa trash ang <xliff:g id="COUNT">^2</xliff:g> na video?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="one">Nag-aalis ng <xliff:g id="COUNT">^1</xliff:g> video sa trash…</item>
+ <item quantity="other">Nag-aalis ng <xliff:g id="COUNT">^1</xliff:g> na video sa trash…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="one">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na alisin sa trash ang <xliff:g id="COUNT">^2</xliff:g> larawan?</item>
<item quantity="other">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na alisin sa trash ang <xliff:g id="COUNT">^2</xliff:g> na larawan?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="one">Nag-aalis ng <xliff:g id="COUNT">^1</xliff:g> larawan sa trash…</item>
+ <item quantity="other">Nag-aalis ng <xliff:g id="COUNT">^1</xliff:g> na larawan sa trash…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="one">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na alisin sa trash ang <xliff:g id="COUNT">^2</xliff:g> item?</item>
<item quantity="other">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na alisin sa trash ang <xliff:g id="COUNT">^2</xliff:g> na item?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="one">Nag-aalis ng <xliff:g id="COUNT">^1</xliff:g> item sa trash…</item>
+ <item quantity="other">Nag-aalis ng <xliff:g id="COUNT">^1</xliff:g> na item sa trash…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="one">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na i-delete ang <xliff:g id="COUNT">^2</xliff:g> audio file?</item>
<item quantity="other">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na i-delete ang <xliff:g id="COUNT">^2</xliff:g> na audio file?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="one">Nagde-delete ng <xliff:g id="COUNT">^1</xliff:g> audio file…</item>
+ <item quantity="other">Nagde-delete ng <xliff:g id="COUNT">^1</xliff:g> na audio file…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="one">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na i-delete ang <xliff:g id="COUNT">^2</xliff:g> video?</item>
<item quantity="other">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na i-delete ang <xliff:g id="COUNT">^2</xliff:g> na video?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="one">Nagde-delete ng <xliff:g id="COUNT">^1</xliff:g> video…</item>
+ <item quantity="other">Nagde-delete ng <xliff:g id="COUNT">^1</xliff:g> na video…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="one">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na i-delete ang <xliff:g id="COUNT">^2</xliff:g> larawan?</item>
<item quantity="other">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na i-delete ang <xliff:g id="COUNT">^2</xliff:g> na larawan?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="one">Nagde-delete ng <xliff:g id="COUNT">^1</xliff:g> larawan…</item>
+ <item quantity="other">Nagde-delete ng <xliff:g id="COUNT">^1</xliff:g> na larawan…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="one">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na i-delete ang <xliff:g id="COUNT">^2</xliff:g> item?</item>
<item quantity="other">Payagan ang <xliff:g id="APP_NAME_1">^1</xliff:g> na i-delete ang <xliff:g id="COUNT">^2</xliff:g> na item?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="one">Nagde-delete ng <xliff:g id="COUNT">^1</xliff:g> item…</item>
+ <item quantity="other">Nagde-delete ng <xliff:g id="COUNT">^1</xliff:g> na item…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"Hindi nakakapagproseso ng mga media file ang <xliff:g id="APP_NAME">%s</xliff:g>"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Nakansela ang pagpoproseso ng media"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Error sa pagpoproseso ng media"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Matagumpay ang pagpoproseso ng media"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Sinimulan ang pagpoproseso ng media"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Pinoproseso ang media…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Kanselahin"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Maghintay"</string>
</resources>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 669eac9..e3efff8 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> uygulamasının <xliff:g id="COUNT">^2</xliff:g> ses dosyasını değiştirmesine izin verilsin mi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> uygulamasının bu ses dosyasını değiştirmesine izin verilsin mi?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ses dosyası değiştiriliyor…</item>
+ <item quantity="one">Ses dosyası değiştiriliyor…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> uygulamasının <xliff:g id="COUNT">^2</xliff:g> videoyu değiştirmesine izin verilsin mi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> uygulamasının bu videoyu değiştirmesine izin verilsin mi?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> video değiştiriliyor…</item>
+ <item quantity="one">Video değiştiriliyor…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> uygulamasının <xliff:g id="COUNT">^2</xliff:g> fotoğrafı değiştirmesine izin verilsin mi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> uygulamasının bu fotoğrafı değiştirmesine izin verilsin mi?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> fotoğraf değiştiriliyor…</item>
+ <item quantity="one">Fotoğraf değiştiriliyor…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> uygulamasının <xliff:g id="COUNT">^2</xliff:g> öğeyi değiştirmesine izin verilsin mi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> uygulamasının bu öğeyi değiştirmesine izin verilsin mi?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> öğe değiştiriliyor…</item>
+ <item quantity="one">Öğe değiştiriliyor…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> uygulamasının <xliff:g id="COUNT">^2</xliff:g> ses dosyasını çöp kutusuna taşımasına izin verilsin mi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> uygulamasının bu ses dosyasını çöp kutusuna taşımasına izin verilsin mi?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ses dosyası çöp kutusuna taşınıyor…</item>
+ <item quantity="one">Ses dosyası çöp kutusuna taşınıyor…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> uygulamasının <xliff:g id="COUNT">^2</xliff:g> videoyu çöp kutusuna taşımasına izin verilsin mi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> uygulamasının bu videoyu çöp kutusuna taşımasına izin verilsin mi?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> video çöp kutusuna taşınıyor…</item>
+ <item quantity="one">Video çöp kutusuna taşınıyor…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> uygulamasının <xliff:g id="COUNT">^2</xliff:g> fotoğrafı çöp kutusuna taşımasına izin verilsin mi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> uygulamasının bu fotoğrafı çöp kutusuna taşımasına izin verilsin mi?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> fotoğraf çöp kutusuna taşınıyor…</item>
+ <item quantity="one">Fotoğraf çöp kutusuna taşınıyor…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> uygulamasının <xliff:g id="COUNT">^2</xliff:g> öğeyi çöp kutusuna taşımasına izin verilsin mi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> uygulamasının bu öğeyi çöp kutusuna taşımasına izin verilsin mi?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> öğe çöp kutusuna taşınıyor…</item>
+ <item quantity="one">Öğe çöp kutusuna taşınıyor…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> uygulamasının <xliff:g id="COUNT">^2</xliff:g> ses dosyasını çöp kutusundan geri yüklemesine izin verilsin mi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> uygulamasının bu ses dosyasını çöp kutusundan geri yüklemesine izin verilsin mi?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ses dosyası çöp kutusundan geri yükleniyor…</item>
+ <item quantity="one">Ses dosyası çöp kutusundan geri yükleniyor…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> uygulamasının <xliff:g id="COUNT">^2</xliff:g> videoyu çöp kutusundan geri yüklemesine izin verilsin mi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> uygulamasının bu videoyu çöp kutusundan geri yüklemesine izin verilsin mi?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> video çöp kutusundan geri yükleniyor…</item>
+ <item quantity="one">Video çöp kutusundan geri yükleniyor…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> uygulamasının <xliff:g id="COUNT">^2</xliff:g> fotoğrafı çöp kutusundan geri yüklemesine izin verilsin mi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> uygulamasının bu fotoğrafı çöp kutusundan geri yüklemesine izin verilsin mi?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> fotoğraf çöp kutusundan geri yükleniyor…</item>
+ <item quantity="one">Fotoğraf çöp kutusundan geri yükleniyor…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> uygulamasının <xliff:g id="COUNT">^2</xliff:g> öğeyi çöp kutusundan geri yüklemesine izin verilsin mi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> uygulamasının bu öğeyi çöp kutusundan geri yüklemesine izin verilsin mi?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> öğe çöp kutusundan geri yükleniyor…</item>
+ <item quantity="one">Öğe çöp kutusundan geri yükleniyor…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> uygulamasının <xliff:g id="COUNT">^2</xliff:g> ses dosyasını silmesine izin verilsin mi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> uygulamasının bu ses dosyasını silmesine izin verilsin mi?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ses dosyası siliniyor…</item>
+ <item quantity="one">Ses dosyası siliniyor…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> uygulamasının <xliff:g id="COUNT">^2</xliff:g> videoyu silmesine izin verilsin mi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> uygulamasının bu videoyu silmesine izin verilsin mi?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> video siliniyor…</item>
+ <item quantity="one">Video siliniyor…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> uygulamasının <xliff:g id="COUNT">^2</xliff:g> fotoğrafı silmesine izin verilsin mi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> uygulamasının bu fotoğrafı silmesine izin verilsin mi?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> fotoğraf siliniyor…</item>
+ <item quantity="one">Fotoğraf siliniyor…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> uygulamasının <xliff:g id="COUNT">^2</xliff:g> öğeyi silmesine izin verilsin mi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> uygulamasının bu öğeyi silmesine izin verilsin mi?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> öğe siliniyor…</item>
+ <item quantity="one">Öğe siliniyor…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g>, medya dosyalarını işleyemez"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Medya işleme iptal edildi"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Medya işleme hatası"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Medya işleme başarılı"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Medya işleme başladı"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Medya işleniyor…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"İptal"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Bekle"</string>
</resources>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 281c8b2..d03fb4c 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -53,94 +53,198 @@
<item quantity="many">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> змінити <xliff:g id="COUNT">^2</xliff:g> аудіофайлів?</item>
<item quantity="other">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> змінити <xliff:g id="COUNT">^2</xliff:g> аудіофайлу?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="one">Змінення <xliff:g id="COUNT">^1</xliff:g> аудіофайлу…</item>
+ <item quantity="few">Змінення <xliff:g id="COUNT">^1</xliff:g> аудіофайлів…</item>
+ <item quantity="many">Змінення <xliff:g id="COUNT">^1</xliff:g> аудіофайлів…</item>
+ <item quantity="other">Змінення <xliff:g id="COUNT">^1</xliff:g> аудіофайлу…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="one">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> змінити <xliff:g id="COUNT">^2</xliff:g> відео?</item>
<item quantity="few">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> змінити <xliff:g id="COUNT">^2</xliff:g> відео?</item>
<item quantity="many">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> змінити <xliff:g id="COUNT">^2</xliff:g> відео?</item>
<item quantity="other">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> змінити <xliff:g id="COUNT">^2</xliff:g> відео?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="one">Змінення <xliff:g id="COUNT">^1</xliff:g> відео…</item>
+ <item quantity="few">Змінення <xliff:g id="COUNT">^1</xliff:g> відео…</item>
+ <item quantity="many">Змінення <xliff:g id="COUNT">^1</xliff:g> відео…</item>
+ <item quantity="other">Змінення <xliff:g id="COUNT">^1</xliff:g> відео…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="one">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> змінити <xliff:g id="COUNT">^2</xliff:g> фотографію?</item>
<item quantity="few">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> змінити <xliff:g id="COUNT">^2</xliff:g> фотографії?</item>
<item quantity="many">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> змінити <xliff:g id="COUNT">^2</xliff:g> фотографій?</item>
<item quantity="other">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> змінити <xliff:g id="COUNT">^2</xliff:g> фотографії?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="one">Змінення <xliff:g id="COUNT">^1</xliff:g> фотографії…</item>
+ <item quantity="few">Змінення <xliff:g id="COUNT">^1</xliff:g> фотографій…</item>
+ <item quantity="many">Змінення <xliff:g id="COUNT">^1</xliff:g> фотографій…</item>
+ <item quantity="other">Змінення <xliff:g id="COUNT">^1</xliff:g> фотографії…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="one">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> змінити <xliff:g id="COUNT">^2</xliff:g> елемент?</item>
<item quantity="few">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> змінити <xliff:g id="COUNT">^2</xliff:g> елементи?</item>
<item quantity="many">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> змінити <xliff:g id="COUNT">^2</xliff:g> елементів?</item>
<item quantity="other">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> змінити <xliff:g id="COUNT">^2</xliff:g> елемента?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="one">Змінення <xliff:g id="COUNT">^1</xliff:g> об\'єкта…</item>
+ <item quantity="few">Змінення <xliff:g id="COUNT">^1</xliff:g> об\'єктів…</item>
+ <item quantity="many">Змінення <xliff:g id="COUNT">^1</xliff:g> об\'єктів…</item>
+ <item quantity="other">Змінення <xliff:g id="COUNT">^1</xliff:g> об\'єкта…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="one">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> перемістити <xliff:g id="COUNT">^2</xliff:g> аудіофайл у кошик?</item>
<item quantity="few">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> перемістити <xliff:g id="COUNT">^2</xliff:g> аудіофайли в кошик?</item>
<item quantity="many">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> перемістити <xliff:g id="COUNT">^2</xliff:g> аудіофайлів у кошик?</item>
<item quantity="other">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> перемістити <xliff:g id="COUNT">^2</xliff:g> аудіофайлу в кошик?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="one">Переміщення <xliff:g id="COUNT">^1</xliff:g> аудіофайлу в кошик…</item>
+ <item quantity="few">Переміщення <xliff:g id="COUNT">^1</xliff:g> аудіофайлів у кошик…</item>
+ <item quantity="many">Переміщення <xliff:g id="COUNT">^1</xliff:g> аудіофайлів у кошик…</item>
+ <item quantity="other">Переміщення <xliff:g id="COUNT">^1</xliff:g> аудіофайлу в кошик…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="one">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> перемістити <xliff:g id="COUNT">^2</xliff:g> відео в кошик?</item>
<item quantity="few">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> перемістити <xliff:g id="COUNT">^2</xliff:g> відео в кошик?</item>
<item quantity="many">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> перемістити <xliff:g id="COUNT">^2</xliff:g> відео в кошик?</item>
<item quantity="other">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> перемістити <xliff:g id="COUNT">^2</xliff:g> відео в кошик?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="one">Переміщення <xliff:g id="COUNT">^1</xliff:g> відео в кошик…</item>
+ <item quantity="few">Переміщення <xliff:g id="COUNT">^1</xliff:g> відео в кошик…</item>
+ <item quantity="many">Переміщення <xliff:g id="COUNT">^1</xliff:g> відео в кошик…</item>
+ <item quantity="other">Переміщення <xliff:g id="COUNT">^1</xliff:g> відео в кошик…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="one">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> перемістити <xliff:g id="COUNT">^2</xliff:g> фотографію в кошик?</item>
<item quantity="few">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> перемістити <xliff:g id="COUNT">^2</xliff:g> фотографії в кошик?</item>
<item quantity="many">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> перемістити <xliff:g id="COUNT">^2</xliff:g> фотографій у кошик?</item>
<item quantity="other">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> перемістити <xliff:g id="COUNT">^2</xliff:g> фотографії в кошик?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="one">Переміщення <xliff:g id="COUNT">^1</xliff:g> фотографії в кошик…</item>
+ <item quantity="few">Переміщення <xliff:g id="COUNT">^1</xliff:g> фотографій у кошик…</item>
+ <item quantity="many">Переміщення <xliff:g id="COUNT">^1</xliff:g> фотографій у кошик…</item>
+ <item quantity="other">Переміщення <xliff:g id="COUNT">^1</xliff:g> фотографії в кошик…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="one">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> перемістити <xliff:g id="COUNT">^2</xliff:g> елемент у кошик?</item>
<item quantity="few">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> перемістити <xliff:g id="COUNT">^2</xliff:g> елементи в кошик?</item>
<item quantity="many">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> перемістити <xliff:g id="COUNT">^2</xliff:g> елементів у кошик?</item>
<item quantity="other">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> перемістити <xliff:g id="COUNT">^2</xliff:g> елемента в кошик?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="one">Переміщення <xliff:g id="COUNT">^1</xliff:g> об\'єкта в кошик…</item>
+ <item quantity="few">Переміщення <xliff:g id="COUNT">^1</xliff:g> об\'єктів у кошик…</item>
+ <item quantity="many">Переміщення <xliff:g id="COUNT">^1</xliff:g> об\'єктів у кошик…</item>
+ <item quantity="other">Переміщення <xliff:g id="COUNT">^1</xliff:g> об\'єкта в кошик…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="one">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> відновити <xliff:g id="COUNT">^2</xliff:g> аудіофайл?</item>
<item quantity="few">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> відновити <xliff:g id="COUNT">^2</xliff:g> аудіофайли?</item>
<item quantity="many">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> відновити <xliff:g id="COUNT">^2</xliff:g> аудіофайлів?</item>
<item quantity="other">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> відновити <xliff:g id="COUNT">^2</xliff:g> аудіофайлу?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="one">Відновлення <xliff:g id="COUNT">^1</xliff:g> аудіофайлу з кошика…</item>
+ <item quantity="few">Відновлення <xliff:g id="COUNT">^1</xliff:g> аудіофайлів із кошика…</item>
+ <item quantity="many">Відновлення <xliff:g id="COUNT">^1</xliff:g> аудіофайлів із кошика…</item>
+ <item quantity="other">Відновлення <xliff:g id="COUNT">^1</xliff:g> аудіофайлу з кошика…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="one">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> відновити <xliff:g id="COUNT">^2</xliff:g> відео?</item>
<item quantity="few">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> відновити <xliff:g id="COUNT">^2</xliff:g> відео?</item>
<item quantity="many">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> відновити <xliff:g id="COUNT">^2</xliff:g> відео?</item>
<item quantity="other">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> відновити <xliff:g id="COUNT">^2</xliff:g> відео?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="one">Відновлення <xliff:g id="COUNT">^1</xliff:g> відео з кошика…</item>
+ <item quantity="few">Відновлення <xliff:g id="COUNT">^1</xliff:g> відео з кошика…</item>
+ <item quantity="many">Відновлення <xliff:g id="COUNT">^1</xliff:g> відео з кошика…</item>
+ <item quantity="other">Відновлення <xliff:g id="COUNT">^1</xliff:g> відео з кошика…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="one">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> відновити <xliff:g id="COUNT">^2</xliff:g> фотографію?</item>
<item quantity="few">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> відновити <xliff:g id="COUNT">^2</xliff:g> фотографії?</item>
<item quantity="many">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> відновити <xliff:g id="COUNT">^2</xliff:g> фотографій?</item>
<item quantity="other">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> відновити <xliff:g id="COUNT">^2</xliff:g> фотографії?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="one">Відновлення <xliff:g id="COUNT">^1</xliff:g> фотографії з кошика…</item>
+ <item quantity="few">Відновлення <xliff:g id="COUNT">^1</xliff:g> фотографій із кошика…</item>
+ <item quantity="many">Відновлення <xliff:g id="COUNT">^1</xliff:g> фотографій із кошика…</item>
+ <item quantity="other">Відновлення <xliff:g id="COUNT">^1</xliff:g> фотографії з кошика…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="one">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> відновити <xliff:g id="COUNT">^2</xliff:g> елемент?</item>
<item quantity="few">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> відновити <xliff:g id="COUNT">^2</xliff:g> елементи?</item>
<item quantity="many">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> відновити <xliff:g id="COUNT">^2</xliff:g> елементів?</item>
<item quantity="other">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> відновити <xliff:g id="COUNT">^2</xliff:g> елемента?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="one">Відновлення <xliff:g id="COUNT">^1</xliff:g> об\'єкта з кошика…</item>
+ <item quantity="few">Відновлення <xliff:g id="COUNT">^1</xliff:g> об\'єктів із кошика…</item>
+ <item quantity="many">Відновлення <xliff:g id="COUNT">^1</xliff:g> об\'єктів із кошика…</item>
+ <item quantity="other">Відновлення <xliff:g id="COUNT">^1</xliff:g> об\'єкта з кошика…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="one">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> видалити <xliff:g id="COUNT">^2</xliff:g> аудіофайл?</item>
<item quantity="few">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> видалити <xliff:g id="COUNT">^2</xliff:g> аудіофайли?</item>
<item quantity="many">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> видалити <xliff:g id="COUNT">^2</xliff:g> аудіофайлів?</item>
<item quantity="other">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> видалити <xliff:g id="COUNT">^2</xliff:g> аудіофайлу?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="one">Видалення <xliff:g id="COUNT">^1</xliff:g> аудіофайлу…</item>
+ <item quantity="few">Видалення <xliff:g id="COUNT">^1</xliff:g> аудіофайлів…</item>
+ <item quantity="many">Видалення <xliff:g id="COUNT">^1</xliff:g> аудіофайлів…</item>
+ <item quantity="other">Видалення <xliff:g id="COUNT">^1</xliff:g> аудіофайлу…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="one">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> видалити <xliff:g id="COUNT">^2</xliff:g> відео?</item>
<item quantity="few">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> видалити <xliff:g id="COUNT">^2</xliff:g> відео?</item>
<item quantity="many">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> видалити <xliff:g id="COUNT">^2</xliff:g> відео?</item>
<item quantity="other">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> видалити <xliff:g id="COUNT">^2</xliff:g> відео?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="one">Видалення <xliff:g id="COUNT">^1</xliff:g> відео…</item>
+ <item quantity="few">Видалення <xliff:g id="COUNT">^1</xliff:g> відео…</item>
+ <item quantity="many">Видалення <xliff:g id="COUNT">^1</xliff:g> відео…</item>
+ <item quantity="other">Видалення <xliff:g id="COUNT">^1</xliff:g> відео…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="one">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> видалити <xliff:g id="COUNT">^2</xliff:g> фотографію?</item>
<item quantity="few">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> видалити <xliff:g id="COUNT">^2</xliff:g> фотографії?</item>
<item quantity="many">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> видалити <xliff:g id="COUNT">^2</xliff:g> фотографій?</item>
<item quantity="other">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> видалити <xliff:g id="COUNT">^2</xliff:g> фотографії?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="one">Видалення <xliff:g id="COUNT">^1</xliff:g> фотографії…</item>
+ <item quantity="few">Видалення <xliff:g id="COUNT">^1</xliff:g> фотографій…</item>
+ <item quantity="many">Видалення <xliff:g id="COUNT">^1</xliff:g> фотографій…</item>
+ <item quantity="other">Видалення <xliff:g id="COUNT">^1</xliff:g> фотографії…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="one">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> видалити <xliff:g id="COUNT">^2</xliff:g> елемент?</item>
<item quantity="few">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> видалити <xliff:g id="COUNT">^2</xliff:g> елементи?</item>
<item quantity="many">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> видалити <xliff:g id="COUNT">^2</xliff:g> елементів?</item>
<item quantity="other">Дозволити додатку <xliff:g id="APP_NAME_1">^1</xliff:g> видалити <xliff:g id="COUNT">^2</xliff:g> елемента?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="one">Видалення <xliff:g id="COUNT">^1</xliff:g> об\'єкта…</item>
+ <item quantity="few">Видалення <xliff:g id="COUNT">^1</xliff:g> об\'єктів…</item>
+ <item quantity="many">Видалення <xliff:g id="COUNT">^1</xliff:g> об\'єктів…</item>
+ <item quantity="other">Видалення <xliff:g id="COUNT">^1</xliff:g> об\'єкта…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"Додаток <xliff:g id="APP_NAME">%s</xliff:g> не може обробляти медіафайли"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Обробку медіафайлів скасовано"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Не вдалось обробити медіафайли"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Обробку медіафайлів завершено"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Почалась обробка медіафайлів"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Обробка медіафайлів…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Скасувати"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Зачекати"</string>
</resources>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index ad6cdf1..63488cf 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> کو <xliff:g id="COUNT">^2</xliff:g> آڈیو فائلز میں ترمیم کرنے کی اجازت دیں؟</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> کو اس آڈیو فائل میں ترمیم کرنے کی اجازت دیں؟</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> آڈیو فائلز میں ترمیم کی جا رہی ہے…</item>
+ <item quantity="one">آڈیو فائل میں ترمیم کی جا رہی ہے…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> کو <xliff:g id="COUNT">^2</xliff:g> ویڈیوز میں ترمیم کرنے کی اجازت دیں؟</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> کو اس ویڈیو میں ترمیم کرنے کی اجازت دیں؟</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ویڈیوز میں ترمیم کی جا رہی ہے…</item>
+ <item quantity="one">ویڈیو میں ترمیم کی جا رہی ہے…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> کو <xliff:g id="COUNT">^2</xliff:g> تصاویر میں ترمیم کرنے کی اجازت دیں؟</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> کو اس تصویر میں ترمیم کرنے کی اجازت دیں؟</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> تصاویر میں ترمیم کی جا رہی ہے…</item>
+ <item quantity="one">تصویر میں ترمیم کی جا رہی ہے…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> کو <xliff:g id="COUNT">^2</xliff:g> آئٹمز میں ترمیم کرنے کی اجازت دیں؟</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> کو اس آئٹم میں ترمیم کرنے کی اجازت دیں؟</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> آئٹمز میں ترمیم کی جا رہی ہے…</item>
+ <item quantity="one">آئٹم میں ترمیم کی جا رہی ہے…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> کو <xliff:g id="COUNT">^2</xliff:g> آڈیو فائلز کو کوڑے دان میں منتقل کرنے کی اجازت دیں؟</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> کو اس آڈیو فائل کو کوڑے دان میں منتقل کرنے کی اجازت دیں؟</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> آڈیو فائلز کو کوڑے دان میں منتقل کیا جا رہا ہے…</item>
+ <item quantity="one">آڈیو فائل کو کوڑے دان میں منتقل کیا جا رہا ہے…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> کو <xliff:g id="COUNT">^2</xliff:g> ویڈیوز کو کوڑے دان میں منتقل کرنے کی اجازت دیں؟</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> کو اس ویڈیو کو کوڑے دان میں منتقل کرنے کی اجازت دیں؟</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ویڈیوز کو کوڑے دان میں منتقل کیا جا رہا ہے…</item>
+ <item quantity="one">ویڈیو کو کوڑے دان میں منتقل کیا جا رہا ہے…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> کو <xliff:g id="COUNT">^2</xliff:g> تصاویر کو کوڑے دان میں منتقل کرنے کی اجازت دیں؟</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> کو اس تصویر کو کوڑے دان میں منتقل کرنے کی اجازت دیں؟</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> تصاویر کو کوڑے دان میں منتقل کیا جا رہا ہے…</item>
+ <item quantity="one">تصویر کو کوڑے دان میں منتقل کیا جا رہا ہے…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> کو <xliff:g id="COUNT">^2</xliff:g> آئٹمز کو کوڑے دان میں منتقل کرنے کی اجازت دیں؟</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> کو اس آئٹم کو کوڑے دان میں منتقل کرنے کی اجازت دیں؟</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> آئٹمز کو کوڑے دان میں منتقل کیا جا رہا ہے…</item>
+ <item quantity="one">آئٹم کو کوڑے دان میں منتقل کیا جا رہا ہے…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> کو <xliff:g id="COUNT">^2</xliff:g> آڈیو فائلز کو کوڑے دان سے باہر منتقل کرنے کی اجازت دیں؟</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> کو اس آڈیو فائل کو کوڑے دان سے باہر منتقل کرنے کی اجازت دیں؟</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> آڈیو فائلز کو کوڑے دان سے باہر منتقل کیا جا ریا ہے…</item>
+ <item quantity="one">آڈیو فائل کو کوڑے دان سے باہر منتقل کیا جا ریا ہے…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> کو <xliff:g id="COUNT">^2</xliff:g> ویڈیوز کو کوڑے دان سے باہر منتقل کرنے کی اجازت دیں؟</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> کو اس ویڈیو کو کوڑے دان سے باہر منتقل کرنے کی اجازت دیں؟</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ویڈیوز کو کوڑے دان سے باہر منتقل کیا جا رہا ہے…</item>
+ <item quantity="one">ویڈیو کو کوڑے دان سے باہر منتقل کیا جا رہا ہے…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> کو <xliff:g id="COUNT">^2</xliff:g> تصاویر کو کوڑے دان سے باہر منتقل کرنے کی اجازت دیں؟</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> کو اس تصویر کو کوڑے دان سے باہر منتقل کرنے کی اجازت دیں؟</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> تصاویر کو کوڑے دان سے باہر منتقل کیا جا رہا ہے…</item>
+ <item quantity="one">تصویر کو کوڑے دان سے باہر منتقل کیا جا رہا ہے…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> کو <xliff:g id="COUNT">^2</xliff:g> آئٹمز کو کوڑے دان سے باہر منتقل کرنے کی اجازت دیں؟</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> کو اس آئٹم کو کوڑے دان سے باہر منتقل کرنے کی اجازت دیں؟</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> آئٹمز کو کوڑے دان سے باہر منتقل کیا جا رہا ہے…</item>
+ <item quantity="one">آئٹم کو کوڑے دان سے باہر منتقل کیا جا رہا ہے…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> کو <xliff:g id="COUNT">^2</xliff:g> آڈیو فائلز کو حذف کرنے کی اجازت دیں؟</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> کو اس آڈیو فائل کو حذف کرنے کی اجازت دیں؟</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> آڈیو فائلز حذف کی جا رہی ہیں…</item>
+ <item quantity="one">آڈیو فائل حذف کی جا رہی ہے…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> کو <xliff:g id="COUNT">^2</xliff:g> ویڈیوز کو حذف کرنے کی اجازت دیں؟</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> کو اس ویڈیو کو حذف کرنے کی اجازت دیں؟</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ویڈیوز حذف کی جا رہی ہیں…</item>
+ <item quantity="one">ویڈیو حذف کی جا رہی ہے…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> کو <xliff:g id="COUNT">^2</xliff:g> تصاویر کو حذف کرنے کی اجازت دیں؟</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> کو اس تصویر کو حذف کرنے کی اجازت دیں؟</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> تصاویر حذف کی جا رہی ہیں…</item>
+ <item quantity="one">تصویر حذف کی جا رہی ہے…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> کو <xliff:g id="COUNT">^2</xliff:g> آئٹمز کو حذف کرنے کی اجازت دیں؟</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> کو اس آئٹم کو حذف کرنے کی اجازت دیں؟</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> آئٹمز حذف کئے جا رہے ہیں…</item>
+ <item quantity="one">آئٹم حذف کیا جا رہا ہے…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> میڈیا کی فائلز پر کارروائی نہیں کر سکتی"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"میڈیا پر کارروائی منسوخ ہو گئی"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"میڈیا پر کارروائی کرنے میں خرابی"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"میڈیا پر کارروائی کامیاب ہو گئی"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"میڈیا پر کارروائی شروع ہو گئی"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"میڈیا پر کارروائی ہو رہی ہے…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"منسوخ کریں"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"انتظار کریں"</string>
</resources>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 0dcad99..168bbf8 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ilovasiga <xliff:g id="COUNT">^2</xliff:g> ta audio faylni oʻzgartirishi uchun ruxsat berilsinmi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ilovasiga bu audio faylni oʻzgartirishi uchun ruxsat berilsinmi?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ta audio fayl oʻzgartirilmoqda…</item>
+ <item quantity="one">Audio fayl oʻzgartirilmoqda…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ilovasiga <xliff:g id="COUNT">^2</xliff:g> ta videoni oʻzgartirishi uchun ruxsat berilsinmi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ilovasiga bu videoni oʻzgartirishi uchun ruxsat berilsinmi?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ta video oʻzgartirilmoqda…</item>
+ <item quantity="one">Video oʻzgartirilmoqda…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ilovasiga <xliff:g id="COUNT">^2</xliff:g> ta suratni oʻzgartirishi uchun ruxsat berilsinmi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ilovasiga bu suratni oʻzgartirishi uchun ruxsat berilsinmi?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ta rasm oʻzgartirilmoqda…</item>
+ <item quantity="one">Rasm oʻzgartirilmoqda…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ilovasiga <xliff:g id="COUNT">^2</xliff:g> ta elementni oʻzgartirishi uchun ruxsat berilsinmi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ilovasiga bu elementni oʻzgartirishi uchun ruxsat berilsinmi?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ta element oʻzgartirilmoqda…</item>
+ <item quantity="one">Element oʻzgartirilmoqda…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ilovasiga <xliff:g id="COUNT">^2</xliff:g> ta audio faylni chiqitdonga tashlashi uchun ruxsat berilsinmi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ilovasiga bu audio faylni chiqitdonga tashlashi uchun ruxsat berilsinmi?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ta audio fayl chiqitdonga tashlanmoqda…</item>
+ <item quantity="one">Audio fayl chiqitdonga tashlanmoqda…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ilovasiga <xliff:g id="COUNT">^2</xliff:g> ta videoni chiqitdonga tashlashi uchun ruxsat berilsinmi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ilovasiga bu videoni chiqitdonga tashlashi uchun ruxsat berilsinmi?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ta video chiqitdonga tashlanmoqda…</item>
+ <item quantity="one">Video chiqitdonga tashlanmoqda…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ilovasiga <xliff:g id="COUNT">^2</xliff:g> ta suratni chiqitdonga tashlashi uchun ruxsat berilsinmi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ilovasiga bu suratni chiqitdonga tashlashi uchun ruxsat berilsinmi?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ta rasm chiqitdonga tashlanmoqda…</item>
+ <item quantity="one">Rasm chiqitdonga tashlanmoqda…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ilovasiga <xliff:g id="COUNT">^2</xliff:g> ta elementni chiqitdonga tashlashi uchun ruxsat berilsinmi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ilovasiga bu elementni chiqitdonga tashlashi uchun ruxsat berilsinmi?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ta element chiqitdonga tashlanmoqda…</item>
+ <item quantity="one">Element chiqitdonga tashlanmoqda…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ilovasiga <xliff:g id="COUNT">^2</xliff:g> ta audio faylni chiqitdondan chiqarib olishi uchun ruxsat berilsinmi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ilovasiga bu audio faylni chiqitdondan chiqarib olishi uchun ruxsat berilsinmi?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ta audio fayl chiqitdondan chiqarilmoqda…</item>
+ <item quantity="one">Audio fayl chiqitdondan chiqarilmoqda…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ilovasiga <xliff:g id="COUNT">^2</xliff:g> ta videoni chiqitdondan chiqarib olishi uchun ruxsat berilsinmi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ilovasiga bu videoni chiqitdondan chiqarib olishi uchun ruxsat berilsinmi?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ta video chiqitdondan chiqarilmoqda…</item>
+ <item quantity="one">Video chiqitdondan chiqarilmoqda…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ilovasiga <xliff:g id="COUNT">^2</xliff:g> ta suratni chiqitdondan chiqarib olishi uchun ruxsat berilsinmi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ilovasiga bu suratni chiqitdondan chiqarib olishi uchun ruxsat berilsinmi?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ta rasm chiqitdondan chiqarilmoqda…</item>
+ <item quantity="one">Rasm chiqitdondan chiqarilmoqda…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ilovasiga <xliff:g id="COUNT">^2</xliff:g> ta elementni chiqitdondan chiqarib olishi uchun ruxsat berilsinmi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ilovasiga bu elementni chiqitdondan chiqarib olishi uchun ruxsat berilsinmi?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ta element chiqitdondan chiqarilmoqda…</item>
+ <item quantity="one">Element chiqitdondan chiqarilmoqda…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ilovasiga <xliff:g id="COUNT">^2</xliff:g> ta audio faylni oʻchirib tashlashi uchun ruxsat berilsinmi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ilovasiga bu audio faylni oʻchirib tashlashi uchun ruxsat berilsinmi?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ta audio fayl oʻchirilmoqda…</item>
+ <item quantity="one">Audio fayl oʻchirilmoqda…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ilovasiga <xliff:g id="COUNT">^2</xliff:g> ta videoni oʻchirib tashlashi uchun ruxsat berilsinmi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ilovasiga bu videoni oʻchirib tashlashi uchun ruxsat berilsinmi?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ta video oʻchirilmoqda…</item>
+ <item quantity="one">Video oʻchirilmoqda…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ilovasiga <xliff:g id="COUNT">^2</xliff:g> ta suratni oʻchirib tashlashi uchun ruxsat berilsinmi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ilovasiga bu suratni oʻchirib tashlashi uchun ruxsat berilsinmi?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ta rasm oʻchirilmoqda…</item>
+ <item quantity="one">Rasm oʻchirilmoqda…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> ilovasiga <xliff:g id="COUNT">^2</xliff:g> ta elementni oʻchirib tashlashi uchun ruxsat berilsinmi?</item>
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> ilovasiga bu elementni oʻchirib tashlashi uchun ruxsat berilsinmi?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other"><xliff:g id="COUNT">^1</xliff:g> ta element oʻchirilmoqda…</item>
+ <item quantity="one">Element oʻchirilmoqda…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> media fayllarni ijro qila olmaydi"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Mediaga ishlov berish bekor qilindi"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Mediaga ishlov berishda xatolik yuz berdi"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Mediga ishlov berildi"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Mediaga ishlov berish boshlandi"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Mediaga ishlov berilmoqda…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Bekor qilish"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Kutish"</string>
</resources>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index d0cbec7..87f6201 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">Cho phép <xliff:g id="APP_NAME_1">^1</xliff:g> sửa đổi <xliff:g id="COUNT">^2</xliff:g> tệp âm thanh?</item>
<item quantity="one">Cho phép <xliff:g id="APP_NAME_0">^1</xliff:g> sửa đổi tệp âm thanh này?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other">Đang sửa đổi <xliff:g id="COUNT">^1</xliff:g> tệp âm thanh…</item>
+ <item quantity="one">Đang sửa đổi tệp âm thanh…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">Cho phép <xliff:g id="APP_NAME_1">^1</xliff:g> sửa đổi <xliff:g id="COUNT">^2</xliff:g> video?</item>
<item quantity="one">Cho phép <xliff:g id="APP_NAME_0">^1</xliff:g> sửa đổi video này?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other">Đang sửa đổi <xliff:g id="COUNT">^1</xliff:g> video…</item>
+ <item quantity="one">Đang sửa đổi video…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">Cho phép <xliff:g id="APP_NAME_1">^1</xliff:g> sửa đổi <xliff:g id="COUNT">^2</xliff:g> ảnh?</item>
<item quantity="one">Cho phép <xliff:g id="APP_NAME_0">^1</xliff:g> sửa đổi ảnh này?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other">Đang sửa đổi <xliff:g id="COUNT">^1</xliff:g> ảnh…</item>
+ <item quantity="one">Đang sửa đổi ảnh…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">Cho phép <xliff:g id="APP_NAME_1">^1</xliff:g> sửa đổi <xliff:g id="COUNT">^2</xliff:g> mục?</item>
<item quantity="one">Cho phép <xliff:g id="APP_NAME_0">^1</xliff:g> sửa đổi mục này?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other">Đang sửa đổi <xliff:g id="COUNT">^1</xliff:g> mục…</item>
+ <item quantity="one">Đang sửa đổi mục…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">Cho phép <xliff:g id="APP_NAME_1">^1</xliff:g> chuyển <xliff:g id="COUNT">^2</xliff:g> tệp âm thanh vào thùng rác?</item>
<item quantity="one">Cho phép <xliff:g id="APP_NAME_0">^1</xliff:g> chuyển tệp âm thanh này vào thùng rác?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other">Đang chuyển <xliff:g id="COUNT">^1</xliff:g> tệp âm thanh vào thùng rác…</item>
+ <item quantity="one">Đang chuyển tệp âm thanh vào thùng rác…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">Cho phép <xliff:g id="APP_NAME_1">^1</xliff:g> chuyển <xliff:g id="COUNT">^2</xliff:g> video vào thùng rác?</item>
<item quantity="one">Cho phép <xliff:g id="APP_NAME_0">^1</xliff:g> chuyển video này vào thùng rác?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other">Đang chuyển <xliff:g id="COUNT">^1</xliff:g> video vào thùng rác…</item>
+ <item quantity="one">Đang chuyển video vào thùng rác…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">Cho phép <xliff:g id="APP_NAME_1">^1</xliff:g> chuyển <xliff:g id="COUNT">^2</xliff:g> ảnh vào thùng rác?</item>
<item quantity="one">Cho phép <xliff:g id="APP_NAME_0">^1</xliff:g> chuyển ảnh này vào thùng rác?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other">Đang chuyển <xliff:g id="COUNT">^1</xliff:g> ảnh vào thùng rác…</item>
+ <item quantity="one">Đang chuyển ảnh vào thùng rác…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">Cho phép <xliff:g id="APP_NAME_1">^1</xliff:g> chuyển <xliff:g id="COUNT">^2</xliff:g> mục vào thùng rác?</item>
<item quantity="one">Cho phép <xliff:g id="APP_NAME_0">^1</xliff:g> chuyển mục này vào thùng rác?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other">Đang chuyển <xliff:g id="COUNT">^1</xliff:g> mục vào thùng rác…</item>
+ <item quantity="one">Đang chuyển mục vào thùng rác…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">Cho phép <xliff:g id="APP_NAME_1">^1</xliff:g> chuyển <xliff:g id="COUNT">^2</xliff:g> tệp âm thanh ra khỏi thùng rác?</item>
<item quantity="one">Cho phép <xliff:g id="APP_NAME_0">^1</xliff:g> chuyển tệp âm thanh này ra khỏi thùng rác?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other">Đang chuyển <xliff:g id="COUNT">^1</xliff:g> tệp âm thanh ra khỏi thùng rác…</item>
+ <item quantity="one">Đang chuyển tệp âm thanh ra khỏi thùng rác…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">Cho phép <xliff:g id="APP_NAME_1">^1</xliff:g> chuyển <xliff:g id="COUNT">^2</xliff:g> video ra khỏi thùng rác?</item>
<item quantity="one">Cho phép <xliff:g id="APP_NAME_0">^1</xliff:g> chuyển video này ra khỏi thùng rác?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other">Đang chuyển <xliff:g id="COUNT">^1</xliff:g> video ra khỏi thùng rác…</item>
+ <item quantity="one">Đang chuyển video ra khỏi thùng rác…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">Cho phép <xliff:g id="APP_NAME_1">^1</xliff:g> chuyển <xliff:g id="COUNT">^2</xliff:g> ảnh ra khỏi thùng rác?</item>
<item quantity="one">Cho phép <xliff:g id="APP_NAME_0">^1</xliff:g> chuyển ảnh này ra khỏi thùng rác?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other">Đang chuyển <xliff:g id="COUNT">^1</xliff:g> ảnh ra khỏi thùng rác…</item>
+ <item quantity="one">Đang chuyển ảnh ra khỏi thùng rác…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">Cho phép <xliff:g id="APP_NAME_1">^1</xliff:g> chuyển <xliff:g id="COUNT">^2</xliff:g> mục ra khỏi thùng rác?</item>
<item quantity="one">Cho phép <xliff:g id="APP_NAME_0">^1</xliff:g> chuyển mục này ra khỏi thùng rác?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other">Đang chuyển <xliff:g id="COUNT">^1</xliff:g> mục ra khỏi thùng rác…</item>
+ <item quantity="one">Đang chuyển mục ra khỏi thùng rác…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">Cho phép <xliff:g id="APP_NAME_1">^1</xliff:g> xóa <xliff:g id="COUNT">^2</xliff:g> tệp âm thanh?</item>
<item quantity="one">Cho phép <xliff:g id="APP_NAME_0">^1</xliff:g> xóa tệp âm thanh này?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other">Đang xóa <xliff:g id="COUNT">^1</xliff:g> tệp âm thanh…</item>
+ <item quantity="one">Đang xóa tệp âm thanh…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">Cho phép <xliff:g id="APP_NAME_1">^1</xliff:g> xóa <xliff:g id="COUNT">^2</xliff:g> video?</item>
<item quantity="one">Cho phép <xliff:g id="APP_NAME_0">^1</xliff:g> xóa video này?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other">Đang xóa <xliff:g id="COUNT">^1</xliff:g> video…</item>
+ <item quantity="one">Đang xóa video…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">Cho phép <xliff:g id="APP_NAME_1">^1</xliff:g> xóa <xliff:g id="COUNT">^2</xliff:g> ảnh?</item>
<item quantity="one">Cho phép <xliff:g id="APP_NAME_0">^1</xliff:g> xóa ảnh này?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other">Đang xóa <xliff:g id="COUNT">^1</xliff:g> ảnh…</item>
+ <item quantity="one">Đang xóa ảnh…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">Cho phép <xliff:g id="APP_NAME_1">^1</xliff:g> xóa <xliff:g id="COUNT">^2</xliff:g> mục?</item>
<item quantity="one">Cho phép <xliff:g id="APP_NAME_0">^1</xliff:g> xóa mục này?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other">Đang xóa <xliff:g id="COUNT">^1</xliff:g> mục…</item>
+ <item quantity="one">Đang xóa mục…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g> không thể xử lý các tệp nội dung nghe nhìn"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Đã hủy quá trình xử lý nội dung nghe nhìn"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Lỗi khi xử lý nội dung nghe nhìn"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Đã xử lý thành công nội dung nghe nhìn"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Đã bắt đầu xử lý nội dung nghe nhìn"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Đang xử lý nội dung nghe nhìn..."</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Hủy"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Đợi"</string>
</resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 6cd41f7..b1f7f7f 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">要允许<xliff:g id="APP_NAME_1">^1</xliff:g>修改这 <xliff:g id="COUNT">^2</xliff:g> 个音频文件吗?</item>
<item quantity="one">要允许<xliff:g id="APP_NAME_0">^1</xliff:g>修改这个音频文件吗?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other">正在修改 <xliff:g id="COUNT">^1</xliff:g> 个音频文件…</item>
+ <item quantity="one">正在修改音频文件…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">要允许<xliff:g id="APP_NAME_1">^1</xliff:g>修改这 <xliff:g id="COUNT">^2</xliff:g> 个视频吗?</item>
<item quantity="one">要允许<xliff:g id="APP_NAME_0">^1</xliff:g>修改这个视频吗?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other">正在修改 <xliff:g id="COUNT">^1</xliff:g> 个视频…</item>
+ <item quantity="one">正在修改视频…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">要允许<xliff:g id="APP_NAME_1">^1</xliff:g>修改这 <xliff:g id="COUNT">^2</xliff:g> 张照片吗?</item>
<item quantity="one">要允许<xliff:g id="APP_NAME_0">^1</xliff:g>修改这张照片吗?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other">正在修改 <xliff:g id="COUNT">^1</xliff:g> 张照片…</item>
+ <item quantity="one">正在修改照片…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">要允许<xliff:g id="APP_NAME_1">^1</xliff:g>修改这 <xliff:g id="COUNT">^2</xliff:g> 项内容吗?</item>
<item quantity="one">要允许<xliff:g id="APP_NAME_0">^1</xliff:g>修改这项内容吗?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other">正在修改 <xliff:g id="COUNT">^1</xliff:g> 项内容…</item>
+ <item quantity="one">正在修改内容…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">要允许<xliff:g id="APP_NAME_1">^1</xliff:g>将这 <xliff:g id="COUNT">^2</xliff:g> 个音频文件移入回收站吗?</item>
<item quantity="one">要允许<xliff:g id="APP_NAME_0">^1</xliff:g>将这个音频文件移入回收站吗?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other">正在将 <xliff:g id="COUNT">^1</xliff:g> 个音频文件移入回收站…</item>
+ <item quantity="one">正在将音频文件移入回收站…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">要允许<xliff:g id="APP_NAME_1">^1</xliff:g>将这 <xliff:g id="COUNT">^2</xliff:g> 个视频移入回收站吗?</item>
<item quantity="one">要允许<xliff:g id="APP_NAME_0">^1</xliff:g>将这个视频移入回收站吗?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other">正在将 <xliff:g id="COUNT">^1</xliff:g> 个视频移入回收站…</item>
+ <item quantity="one">正在将视频移入回收站…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">要允许<xliff:g id="APP_NAME_1">^1</xliff:g>将这 <xliff:g id="COUNT">^2</xliff:g> 张照片移入回收站吗?</item>
<item quantity="one">要允许<xliff:g id="APP_NAME_0">^1</xliff:g>将这张照片移入回收站吗?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other">正在将 <xliff:g id="COUNT">^1</xliff:g> 张照片移入回收站…</item>
+ <item quantity="one">正在将照片移入回收站…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">要允许<xliff:g id="APP_NAME_1">^1</xliff:g>将这 <xliff:g id="COUNT">^2</xliff:g> 项内容移入回收站吗?</item>
<item quantity="one">要允许<xliff:g id="APP_NAME_0">^1</xliff:g>将这项内容移入回收站吗?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other">正在将 <xliff:g id="COUNT">^1</xliff:g> 项内容移入回收站…</item>
+ <item quantity="one">正在将内容移入回收站…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">要允许<xliff:g id="APP_NAME_1">^1</xliff:g>将这 <xliff:g id="COUNT">^2</xliff:g> 个音频文件从回收站中移出吗?</item>
<item quantity="one">要允许<xliff:g id="APP_NAME_0">^1</xliff:g>将这个音频文件从回收站中移出吗?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other">正在将 <xliff:g id="COUNT">^1</xliff:g> 个音频文件从回收站中移出…</item>
+ <item quantity="one">正在将音频文件从回收站中移出…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">要允许<xliff:g id="APP_NAME_1">^1</xliff:g>将这 <xliff:g id="COUNT">^2</xliff:g> 个视频从回收站中移出吗?</item>
<item quantity="one">要允许<xliff:g id="APP_NAME_0">^1</xliff:g>将这个视频从回收站中移出吗?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other">正在将 <xliff:g id="COUNT">^1</xliff:g> 个视频从回收站中移出…</item>
+ <item quantity="one">正在将视频从回收站中移出…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">要允许<xliff:g id="APP_NAME_1">^1</xliff:g>将这 <xliff:g id="COUNT">^2</xliff:g> 张照片从回收站中移出吗?</item>
<item quantity="one">要允许<xliff:g id="APP_NAME_0">^1</xliff:g>将这张照片从回收站中移出吗?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other">正在将 <xliff:g id="COUNT">^1</xliff:g> 张照片从回收站中移出…</item>
+ <item quantity="one">正在将照片从回收站中移出…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">要允许<xliff:g id="APP_NAME_1">^1</xliff:g>将这 <xliff:g id="COUNT">^2</xliff:g> 项内容从回收站中移出吗?</item>
<item quantity="one">要允许<xliff:g id="APP_NAME_0">^1</xliff:g>将这项内容从回收站中移出吗?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other">正在将 <xliff:g id="COUNT">^1</xliff:g> 项内容从回收站中移出…</item>
+ <item quantity="one">正在将内容从回收站中移出…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">要允许<xliff:g id="APP_NAME_1">^1</xliff:g>删除这 <xliff:g id="COUNT">^2</xliff:g> 个音频文件吗?</item>
<item quantity="one">要允许<xliff:g id="APP_NAME_0">^1</xliff:g>删除这个音频文件吗?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other">正在删除 <xliff:g id="COUNT">^1</xliff:g> 个音频文件…</item>
+ <item quantity="one">正在删除音频文件…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">要允许<xliff:g id="APP_NAME_1">^1</xliff:g>删除这 <xliff:g id="COUNT">^2</xliff:g> 个视频吗?</item>
<item quantity="one">要允许<xliff:g id="APP_NAME_0">^1</xliff:g>删除这个视频吗?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other">正在删除 <xliff:g id="COUNT">^1</xliff:g> 个视频…</item>
+ <item quantity="one">正在删除视频…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">要允许<xliff:g id="APP_NAME_1">^1</xliff:g>删除这 <xliff:g id="COUNT">^2</xliff:g> 张照片吗?</item>
<item quantity="one">要允许<xliff:g id="APP_NAME_0">^1</xliff:g>删除这张照片吗?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other">正在删除 <xliff:g id="COUNT">^1</xliff:g> 张照片…</item>
+ <item quantity="one">正在删除照片…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">要允许<xliff:g id="APP_NAME_1">^1</xliff:g>删除这 <xliff:g id="COUNT">^2</xliff:g> 项内容吗?</item>
<item quantity="one">要允许<xliff:g id="APP_NAME_0">^1</xliff:g>删除这项内容吗?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other">正在删除 <xliff:g id="COUNT">^1</xliff:g> 项内容…</item>
+ <item quantity="one">正在删除内容…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"<xliff:g id="APP_NAME">%s</xliff:g>无法处理媒体文件"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"已取消处理媒体内容"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"处理媒体内容时出错"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"已成功处理媒体内容"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"已开始处理媒体内容"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"正在处理媒体内容…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"取消"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"等待"</string>
</resources>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 3243f9b..51d8c9e 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">允許 <xliff:g id="APP_NAME_1">^1</xliff:g> 修改 <xliff:g id="COUNT">^2</xliff:g> 部影片嗎?</item>
<item quantity="one">允許 <xliff:g id="APP_NAME_0">^1</xliff:g> 修改此影片嗎?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other">正在修改 <xliff:g id="COUNT">^1</xliff:g> 個音訊檔案…</item>
+ <item quantity="one">正在修改音訊檔案…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">允許 <xliff:g id="APP_NAME_1">^1</xliff:g> 修改 <xliff:g id="COUNT">^2</xliff:g> 部影片嗎?</item>
<item quantity="one">允許 <xliff:g id="APP_NAME_0">^1</xliff:g> 修改此影片嗎?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other">正在修改 <xliff:g id="COUNT">^1</xliff:g> 部影片…</item>
+ <item quantity="one">正在修改影片…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">允許 <xliff:g id="APP_NAME_1">^1</xliff:g> 修改 <xliff:g id="COUNT">^2</xliff:g> 張相片嗎?</item>
<item quantity="one">允許 <xliff:g id="APP_NAME_0">^1</xliff:g> 修改此相片嗎?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other">正在修改 <xliff:g id="COUNT">^1</xliff:g> 張相片…</item>
+ <item quantity="one">正在修改相片…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">允許 <xliff:g id="APP_NAME_1">^1</xliff:g> 修改 <xliff:g id="COUNT">^2</xliff:g> 個項目嗎?</item>
<item quantity="one">允許 <xliff:g id="APP_NAME_0">^1</xliff:g> 修改此項目嗎?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other">正在修改 <xliff:g id="COUNT">^1</xliff:g> 個項目…</item>
+ <item quantity="one">正在修改項目…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">允許 <xliff:g id="APP_NAME_1">^1</xliff:g> 將 <xliff:g id="COUNT">^2</xliff:g> 個音訊檔案移至垃圾桶嗎?</item>
<item quantity="one">允許 <xliff:g id="APP_NAME_0">^1</xliff:g> 將此音訊檔案移至垃圾桶嗎?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other">正在將 <xliff:g id="COUNT">^1</xliff:g> 個音訊檔案移至垃圾桶…</item>
+ <item quantity="one">正在將音訊檔案移至垃圾桶…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">允許 <xliff:g id="APP_NAME_1">^1</xliff:g> 將 <xliff:g id="COUNT">^2</xliff:g> 部影片移至垃圾桶嗎?</item>
<item quantity="one">允許 <xliff:g id="APP_NAME_0">^1</xliff:g> 將此影片移至垃圾桶嗎?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other">正在將 <xliff:g id="COUNT">^1</xliff:g> 部影片移至垃圾桶…</item>
+ <item quantity="one">正在將影片移至垃圾桶…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">允許 <xliff:g id="APP_NAME_1">^1</xliff:g> 將 <xliff:g id="COUNT">^2</xliff:g> 張相片移至垃圾桶嗎?</item>
<item quantity="one">允許 <xliff:g id="APP_NAME_0">^1</xliff:g> 將此相片移至垃圾桶嗎?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other">正在將 <xliff:g id="COUNT">^1</xliff:g> 張相片移至垃圾桶…</item>
+ <item quantity="one">正在將相片移至垃圾桶…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">允許 <xliff:g id="APP_NAME_1">^1</xliff:g> 將 <xliff:g id="COUNT">^2</xliff:g> 個項目移至垃圾桶嗎?</item>
<item quantity="one">允許 <xliff:g id="APP_NAME_0">^1</xliff:g> 將此項目移至垃圾桶嗎?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other">正在將 <xliff:g id="COUNT">^1</xliff:g> 個項目移至垃圾桶…</item>
+ <item quantity="one">正在將項目移至垃圾桶…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">允許 <xliff:g id="APP_NAME_1">^1</xliff:g> 將 <xliff:g id="COUNT">^2</xliff:g> 個音訊檔案移出垃圾桶嗎?</item>
<item quantity="one">允許 <xliff:g id="APP_NAME_0">^1</xliff:g> 將此音訊檔案移出垃圾桶嗎?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other">正在將 <xliff:g id="COUNT">^1</xliff:g> 個音訊檔案移出垃圾桶…</item>
+ <item quantity="one">正在將音訊檔案移出垃圾桶…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">允許 <xliff:g id="APP_NAME_1">^1</xliff:g> 將 <xliff:g id="COUNT">^2</xliff:g> 部影片移出垃圾桶嗎?</item>
<item quantity="one">允許 <xliff:g id="APP_NAME_0">^1</xliff:g> 將此影片移出垃圾桶嗎?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other">正在將 <xliff:g id="COUNT">^1</xliff:g> 部影片移出垃圾桶…</item>
+ <item quantity="one">正在將影片移出垃圾桶…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">允許 <xliff:g id="APP_NAME_1">^1</xliff:g> 將 <xliff:g id="COUNT">^2</xliff:g> 張相片移出垃圾桶嗎?</item>
<item quantity="one">允許 <xliff:g id="APP_NAME_0">^1</xliff:g> 將此相片移出垃圾桶嗎?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other">正在將 <xliff:g id="COUNT">^1</xliff:g> 張相片移出垃圾桶…</item>
+ <item quantity="one">正在將相片移出垃圾桶…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">允許 <xliff:g id="APP_NAME_1">^1</xliff:g> 將 <xliff:g id="COUNT">^2</xliff:g> 個項目移出垃圾桶嗎?</item>
<item quantity="one">允許 <xliff:g id="APP_NAME_0">^1</xliff:g> 將此項目移出垃圾桶嗎?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other">正在將 <xliff:g id="COUNT">^1</xliff:g> 個項目移出垃圾桶…</item>
+ <item quantity="one">正在將項目移出垃圾桶…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">允許 <xliff:g id="APP_NAME_1">^1</xliff:g> 刪除 <xliff:g id="COUNT">^2</xliff:g> 個音訊檔案嗎?</item>
<item quantity="one">允許 <xliff:g id="APP_NAME_0">^1</xliff:g> 刪除此音訊檔案嗎?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other">正在刪除 <xliff:g id="COUNT">^1</xliff:g> 個音訊檔案…</item>
+ <item quantity="one">正在刪除音訊檔案…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">允許 <xliff:g id="APP_NAME_1">^1</xliff:g> 刪除 <xliff:g id="COUNT">^2</xliff:g> 部影片嗎?</item>
<item quantity="one">允許 <xliff:g id="APP_NAME_0">^1</xliff:g> 刪除此影片嗎?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other">正在刪除 <xliff:g id="COUNT">^1</xliff:g> 部影片…</item>
+ <item quantity="one">正在刪除影片…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">允許 <xliff:g id="APP_NAME_1">^1</xliff:g> 刪除 <xliff:g id="COUNT">^2</xliff:g> 張相片嗎?</item>
<item quantity="one">允許 <xliff:g id="APP_NAME_0">^1</xliff:g> 刪除此相片嗎?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other">正在刪除 <xliff:g id="COUNT">^1</xliff:g> 張相片…</item>
+ <item quantity="one">正在刪除相片…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">允許 <xliff:g id="APP_NAME_1">^1</xliff:g> 刪除 <xliff:g id="COUNT">^2</xliff:g> 個項目嗎?</item>
<item quantity="one">允許 <xliff:g id="APP_NAME_0">^1</xliff:g> 刪除此項目嗎?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other">正在刪除 <xliff:g id="COUNT">^1</xliff:g> 個項目…</item>
+ <item quantity="one">正在刪除項目…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"「<xliff:g id="APP_NAME">%s</xliff:g>」無法處理媒體檔案"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"已取消處理媒體"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"處理媒體時發生錯誤"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"處理媒體成功"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"已開始處理媒體"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"正在處理媒體…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"取消"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"等待"</string>
</resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 1a37210..a67a29e 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -47,64 +47,136 @@
<item quantity="other">要允許「<xliff:g id="APP_NAME_1">^1</xliff:g>」修改這 <xliff:g id="COUNT">^2</xliff:g> 個音訊檔案嗎?</item>
<item quantity="one">要允許「<xliff:g id="APP_NAME_0">^1</xliff:g>」修改這個音訊檔案嗎?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="other">正在修改 <xliff:g id="COUNT">^1</xliff:g> 個音訊檔案…</item>
+ <item quantity="one">正在修改音訊檔案…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="other">要允許「<xliff:g id="APP_NAME_1">^1</xliff:g>」修改這 <xliff:g id="COUNT">^2</xliff:g> 部影片嗎?</item>
<item quantity="one">要允許「<xliff:g id="APP_NAME_0">^1</xliff:g>」修改這部影片嗎?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="other">正在修改 <xliff:g id="COUNT">^1</xliff:g> 部影片…</item>
+ <item quantity="one">正在修改影片…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="other">要允許「<xliff:g id="APP_NAME_1">^1</xliff:g>」修改這 <xliff:g id="COUNT">^2</xliff:g> 張相片嗎?</item>
<item quantity="one">要允許「<xliff:g id="APP_NAME_0">^1</xliff:g>」修改這張相片嗎?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="other">正在修改 <xliff:g id="COUNT">^1</xliff:g> 張相片…</item>
+ <item quantity="one">正在修改相片…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="other">要允許「<xliff:g id="APP_NAME_1">^1</xliff:g>」修改這 <xliff:g id="COUNT">^2</xliff:g> 個項目嗎?</item>
<item quantity="one">要允許「<xliff:g id="APP_NAME_0">^1</xliff:g>」修改這個項目嗎?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="other">正在修改 <xliff:g id="COUNT">^1</xliff:g> 個項目…</item>
+ <item quantity="one">正在修改項目…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="other">要允許「<xliff:g id="APP_NAME_1">^1</xliff:g>」將這 <xliff:g id="COUNT">^2</xliff:g> 個音訊檔案移至垃圾桶嗎?</item>
<item quantity="one">要允許「<xliff:g id="APP_NAME_0">^1</xliff:g>」將這個音訊檔案移至垃圾桶嗎?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="other">正在將 <xliff:g id="COUNT">^1</xliff:g> 個音訊檔案移入垃圾桶…</item>
+ <item quantity="one">正在將音訊檔案移入垃圾桶…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="other">要允許「<xliff:g id="APP_NAME_1">^1</xliff:g>」將這 <xliff:g id="COUNT">^2</xliff:g> 部影片移至垃圾桶嗎?</item>
<item quantity="one">要允許「<xliff:g id="APP_NAME_0">^1</xliff:g>」將這部影片移至垃圾桶嗎?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="other">正在將 <xliff:g id="COUNT">^1</xliff:g> 部影片移入垃圾桶…</item>
+ <item quantity="one">正在將影片移入垃圾桶…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="other">要允許「<xliff:g id="APP_NAME_1">^1</xliff:g>」將這 <xliff:g id="COUNT">^2</xliff:g> 張相片移至垃圾桶嗎?</item>
<item quantity="one">要允許「<xliff:g id="APP_NAME_0">^1</xliff:g>」將這張相片移至垃圾桶嗎?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="other">正在將 <xliff:g id="COUNT">^1</xliff:g> 張相片移入垃圾桶…</item>
+ <item quantity="one">正在將相片移入垃圾桶…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="other">要允許「<xliff:g id="APP_NAME_1">^1</xliff:g>」將這 <xliff:g id="COUNT">^2</xliff:g> 個項目移至垃圾桶嗎?</item>
<item quantity="one">要允許「<xliff:g id="APP_NAME_0">^1</xliff:g>」將這個項目移至垃圾桶嗎?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="other">正在將 <xliff:g id="COUNT">^1</xliff:g> 個項目移入垃圾桶…</item>
+ <item quantity="one">正在將項目移入垃圾桶…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="other">要允許「<xliff:g id="APP_NAME_1">^1</xliff:g>」將這 <xliff:g id="COUNT">^2</xliff:g> 個音訊檔案移出垃圾桶嗎?</item>
<item quantity="one">要允許「<xliff:g id="APP_NAME_0">^1</xliff:g>」將這個音訊檔案移出垃圾桶嗎?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="other">正在將 <xliff:g id="COUNT">^1</xliff:g> 個音訊檔案移出垃圾桶…</item>
+ <item quantity="one">正在將音訊檔案移出垃圾桶…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="other">要允許「<xliff:g id="APP_NAME_1">^1</xliff:g>」將這 <xliff:g id="COUNT">^2</xliff:g> 部影片移出垃圾桶嗎?</item>
<item quantity="one">要允許「<xliff:g id="APP_NAME_0">^1</xliff:g>」將這部影片移出垃圾桶嗎?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="other">正在將 <xliff:g id="COUNT">^1</xliff:g> 部影片移出垃圾桶…</item>
+ <item quantity="one">正在將影片移出垃圾桶…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="other">要允許「<xliff:g id="APP_NAME_1">^1</xliff:g>」將這 <xliff:g id="COUNT">^2</xliff:g> 張相片移出垃圾桶嗎?</item>
<item quantity="one">要允許「<xliff:g id="APP_NAME_0">^1</xliff:g>」將這張相片移出垃圾桶嗎?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="other">正在將 <xliff:g id="COUNT">^1</xliff:g> 張相片移出垃圾桶…</item>
+ <item quantity="one">正在將相片移出垃圾桶…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="other">要允許「<xliff:g id="APP_NAME_1">^1</xliff:g>」將這 <xliff:g id="COUNT">^2</xliff:g> 個項目移出垃圾桶嗎?</item>
<item quantity="one">要允許「<xliff:g id="APP_NAME_0">^1</xliff:g>」將這個項目移出垃圾桶嗎?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="other">正在將 <xliff:g id="COUNT">^1</xliff:g> 個項目移出垃圾桶…</item>
+ <item quantity="one">正在將項目移出垃圾桶…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="other">要允許「<xliff:g id="APP_NAME_1">^1</xliff:g>」刪除這 <xliff:g id="COUNT">^2</xliff:g> 個音訊檔案嗎?</item>
<item quantity="one">要允許「<xliff:g id="APP_NAME_0">^1</xliff:g>」刪除這個音訊檔案嗎?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="other">正在刪除 <xliff:g id="COUNT">^1</xliff:g> 個音訊檔案…</item>
+ <item quantity="one">正在刪除音訊檔案…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="other">要允許「<xliff:g id="APP_NAME_1">^1</xliff:g>」刪除這 <xliff:g id="COUNT">^2</xliff:g> 部影片嗎?</item>
<item quantity="one">要允許「<xliff:g id="APP_NAME_0">^1</xliff:g>」刪除這部影片嗎?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="other">正在刪除 <xliff:g id="COUNT">^1</xliff:g> 部影片…</item>
+ <item quantity="one">正在刪除影片…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="other">要允許「<xliff:g id="APP_NAME_1">^1</xliff:g>」刪除這 <xliff:g id="COUNT">^2</xliff:g> 張相片嗎?</item>
<item quantity="one">要允許「<xliff:g id="APP_NAME_0">^1</xliff:g>」刪除這張相片嗎?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="other">刪除 <xliff:g id="COUNT">^1</xliff:g> 張相片…</item>
+ <item quantity="one">正在刪除相片…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="other">要允許「<xliff:g id="APP_NAME_1">^1</xliff:g>」刪除這 <xliff:g id="COUNT">^2</xliff:g> 個項目嗎?</item>
<item quantity="one">要允許「<xliff:g id="APP_NAME_0">^1</xliff:g>」刪除這個項目嗎?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="other">正在刪除 <xliff:g id="COUNT">^1</xliff:g> 個項目…</item>
+ <item quantity="one">正在刪除項目…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"「<xliff:g id="APP_NAME">%s</xliff:g>」無法處理媒體檔案"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"已取消處理媒體"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"處理媒體時發生錯誤"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"媒體處理成功"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"已開始處理媒體"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"正在處理媒體…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"取消"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"等待"</string>
</resources>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index e2f528d..36d01de 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -47,64 +47,136 @@
<item quantity="one">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukuguqula amafayela omsindo angu-<xliff:g id="COUNT">^2</xliff:g>?</item>
<item quantity="other">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukuguqula amafayela omsindo angu-<xliff:g id="COUNT">^2</xliff:g>?</item>
</plurals>
+ <plurals name="permission_progress_write_audio" formatted="false" msgid="3757901555809850632">
+ <item quantity="one">Ilungisa amafayela womsindo angu-<xliff:g id="COUNT">^1</xliff:g>…</item>
+ <item quantity="other">Ilungisa amafayela womsindo angu-<xliff:g id="COUNT">^1</xliff:g>…</item>
+ </plurals>
<plurals name="permission_write_video" formatted="false" msgid="1098082003326873084">
<item quantity="one">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukuguqula amavidiyo angu-<xliff:g id="COUNT">^2</xliff:g>?</item>
<item quantity="other">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukuguqula amavidiyo angu-<xliff:g id="COUNT">^2</xliff:g>?</item>
</plurals>
+ <plurals name="permission_progress_write_video" formatted="false" msgid="2244685155683762411">
+ <item quantity="one">Ilungisa amavidiyo angu-<xliff:g id="COUNT">^1</xliff:g>…</item>
+ <item quantity="other">Ilungisa amavidiyo angu-<xliff:g id="COUNT">^1</xliff:g>…</item>
+ </plurals>
<plurals name="permission_write_image" formatted="false" msgid="748745548893845892">
<item quantity="one">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukuguqula izithombe ezingu-<xliff:g id="COUNT">^2</xliff:g>?</item>
<item quantity="other">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukuguqula izithombe ezingu-<xliff:g id="COUNT">^2</xliff:g>?</item>
</plurals>
+ <plurals name="permission_progress_write_image" formatted="false" msgid="9126939088839855157">
+ <item quantity="one">Ilungisa izithombe ezingu-<xliff:g id="COUNT">^1</xliff:g>…</item>
+ <item quantity="other">Ilungisa izithombe ezingu-<xliff:g id="COUNT">^1</xliff:g>…</item>
+ </plurals>
<plurals name="permission_write_generic" formatted="false" msgid="3270172714743671779">
<item quantity="one">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukuguqula izinto ezingu-<xliff:g id="COUNT">^2</xliff:g>?</item>
<item quantity="other">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukuguqula izinto ezingu-<xliff:g id="COUNT">^2</xliff:g>?</item>
</plurals>
+ <plurals name="permission_progress_write_generic" formatted="false" msgid="1928961922186705621">
+ <item quantity="one">Ilungisa izinto ezingu-<xliff:g id="COUNT">^1</xliff:g>…</item>
+ <item quantity="other">Ilungisa izinto ezingu-<xliff:g id="COUNT">^1</xliff:g>…</item>
+ </plurals>
<plurals name="permission_trash_audio" formatted="false" msgid="8907813869381755423">
<item quantity="one">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukuhambisa amafayela omsindo angu-<xliff:g id="COUNT">^2</xliff:g> kudoti?</item>
<item quantity="other">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukuhambisa amafayela omsindo angu-<xliff:g id="COUNT">^2</xliff:g> kudoti?</item>
</plurals>
+ <plurals name="permission_progress_trash_audio" formatted="false" msgid="8142631134676951388">
+ <item quantity="one">Ihambisa amafayela womsindo angu-<xliff:g id="COUNT">^1</xliff:g> kudoti…</item>
+ <item quantity="other">Ihambisa amafayela womsindo angu-<xliff:g id="COUNT">^1</xliff:g> kudoti…</item>
+ </plurals>
<plurals name="permission_trash_video" formatted="false" msgid="4672871911555787438">
<item quantity="one">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukuhambisa amavidiyo angu-<xliff:g id="COUNT">^2</xliff:g> kudoti?</item>
<item quantity="other">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukuhambisa amavidiyo angu-<xliff:g id="COUNT">^2</xliff:g> kudoti?</item>
</plurals>
+ <plurals name="permission_progress_trash_video" formatted="false" msgid="2566683722600149120">
+ <item quantity="one">Ihambisa amavidiyo angu-<xliff:g id="COUNT">^1</xliff:g> kudoti…</item>
+ <item quantity="other">Ihambisa amavidiyo angu-<xliff:g id="COUNT">^1</xliff:g> kudoti…</item>
+ </plurals>
<plurals name="permission_trash_image" formatted="false" msgid="6400475304599873227">
<item quantity="one">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukuhambisa izithombe ezingu ku-<xliff:g id="COUNT">^2</xliff:g>?</item>
<item quantity="other">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukuhambisa izithombe ezingu ku-<xliff:g id="COUNT">^2</xliff:g>?</item>
</plurals>
+ <plurals name="permission_progress_trash_image" formatted="false" msgid="4529586663770971476">
+ <item quantity="one">Ihambisa izithombe ezingu-<xliff:g id="COUNT">^1</xliff:g> kudoti…</item>
+ <item quantity="other">Ihambisa izithombe ezingu-<xliff:g id="COUNT">^1</xliff:g> kudoti…</item>
+ </plurals>
<plurals name="permission_trash_generic" formatted="false" msgid="3814167365075039711">
<item quantity="one">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukuhambisa izinto ezingu-<xliff:g id="COUNT">^2</xliff:g> kudoti?</item>
<item quantity="other">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukuhambisa izinto ezingu-<xliff:g id="COUNT">^2</xliff:g> kudoti?</item>
</plurals>
+ <plurals name="permission_progress_trash_generic" formatted="false" msgid="6995141190896908381">
+ <item quantity="one">Ihambisa izinto ezingu-<xliff:g id="COUNT">^1</xliff:g> kudoti…</item>
+ <item quantity="other">Ihambisa izinto ezingu-<xliff:g id="COUNT">^1</xliff:g> kudoti…</item>
+ </plurals>
<plurals name="permission_untrash_audio" formatted="false" msgid="7795265980168966321">
<item quantity="one">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukuhambisa amafayela omsindo angu-<xliff:g id="COUNT">^2</xliff:g> ngaphandle kwedoti?</item>
<item quantity="other">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukuhambisa amafayela omsindo angu-<xliff:g id="COUNT">^2</xliff:g> ngaphandle kwedoti?</item>
</plurals>
+ <plurals name="permission_progress_untrash_audio" formatted="false" msgid="4047200387122043006">
+ <item quantity="one">Ikhipha amafayela omsindo angu-<xliff:g id="COUNT">^1</xliff:g> kudoti…</item>
+ <item quantity="other">Ikhipha amafayela omsindo angu-<xliff:g id="COUNT">^1</xliff:g> kudoti…</item>
+ </plurals>
<plurals name="permission_untrash_video" formatted="false" msgid="332894888445508879">
<item quantity="one">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukuhambisa amavidiyo angu-<xliff:g id="COUNT">^2</xliff:g> ngaphandle kwedoti?</item>
<item quantity="other">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukuhambisa amavidiyo angu-<xliff:g id="COUNT">^2</xliff:g> ngaphandle kwedoti?</item>
</plurals>
+ <plurals name="permission_progress_untrash_video" formatted="false" msgid="7996233128375495458">
+ <item quantity="one">Ikhipha amavidiyo angu-<xliff:g id="COUNT">^1</xliff:g> kudoti…</item>
+ <item quantity="other">Ikhipha amavidiyo angu-<xliff:g id="COUNT">^1</xliff:g> kudoti…</item>
+ </plurals>
<plurals name="permission_untrash_image" formatted="false" msgid="7024071378733595056">
<item quantity="one">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukuhambisa izithombe ezingu-<xliff:g id="COUNT">^2</xliff:g> ngaphandle kwedoti?</item>
<item quantity="other">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukuhambisa izithombe ezingu-<xliff:g id="COUNT">^2</xliff:g> ngaphandle kwedoti?</item>
</plurals>
+ <plurals name="permission_progress_untrash_image" formatted="false" msgid="3473769131910926122">
+ <item quantity="one">Ikhipha izithombe ezingu-<xliff:g id="COUNT">^1</xliff:g> kudoti…</item>
+ <item quantity="other">Ikhipha izithombe ezingu-<xliff:g id="COUNT">^1</xliff:g> kudoti…</item>
+ </plurals>
<plurals name="permission_untrash_generic" formatted="false" msgid="6872817093731198374">
<item quantity="one">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukuhambisa izinto ezingu-<xliff:g id="COUNT">^2</xliff:g> ngaphandle kwedoti?</item>
<item quantity="other">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukuhambisa izinto ezingu-<xliff:g id="COUNT">^2</xliff:g> ngaphandle kwedoti?</item>
</plurals>
+ <plurals name="permission_progress_untrash_generic" formatted="false" msgid="263867753672461510">
+ <item quantity="one">Ikhipha izinto ezingu-<xliff:g id="COUNT">^1</xliff:g> kudoti…</item>
+ <item quantity="other">Ikhipha izinto ezingu-<xliff:g id="COUNT">^1</xliff:g> kudoti…</item>
+ </plurals>
<plurals name="permission_delete_audio" formatted="false" msgid="6848547621165184719">
<item quantity="one">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukususa amafayela omsindo angu-<xliff:g id="COUNT">^2</xliff:g>?</item>
<item quantity="other">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukususa amafayela omsindo angu-<xliff:g id="COUNT">^2</xliff:g>?</item>
</plurals>
+ <plurals name="permission_progress_delete_audio" formatted="false" msgid="8579231060666743501">
+ <item quantity="one">Isusa amafayela omsindo angu-<xliff:g id="COUNT">^1</xliff:g>…</item>
+ <item quantity="other">Isusa amafayela omsindo angu-<xliff:g id="COUNT">^1</xliff:g>…</item>
+ </plurals>
<plurals name="permission_delete_video" formatted="false" msgid="1251942606336748563">
<item quantity="one">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukususa amavidiyo angu-<xliff:g id="COUNT">^2</xliff:g>?</item>
<item quantity="other">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukususa amavidiyo angu-<xliff:g id="COUNT">^2</xliff:g>?</item>
</plurals>
+ <plurals name="permission_progress_delete_video" formatted="false" msgid="4349991290732459111">
+ <item quantity="one">Isusa amavidiyo angu-<xliff:g id="COUNT">^1</xliff:g>…</item>
+ <item quantity="other">Isusa amavidiyo angu-<xliff:g id="COUNT">^1</xliff:g>…</item>
+ </plurals>
<plurals name="permission_delete_image" formatted="false" msgid="2303409455224710111">
<item quantity="one">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukususa izithombe ezingu-<xliff:g id="COUNT">^2</xliff:g>?</item>
<item quantity="other">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukususa izithombe ezingu-<xliff:g id="COUNT">^2</xliff:g>?</item>
</plurals>
+ <plurals name="permission_progress_delete_image" formatted="false" msgid="118648854886957046">
+ <item quantity="one">Isusa izithombe ezingu-<xliff:g id="COUNT">^1</xliff:g>…</item>
+ <item quantity="other">Isusa izithombe ezingu-<xliff:g id="COUNT">^1</xliff:g>…</item>
+ </plurals>
<plurals name="permission_delete_generic" formatted="false" msgid="1412218850351841181">
<item quantity="one">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukususa izinto ezingu-<xliff:g id="COUNT">^2</xliff:g>?</item>
<item quantity="other">Vumela i-<xliff:g id="APP_NAME_1">^1</xliff:g> ukususa izinto ezingu-<xliff:g id="COUNT">^2</xliff:g>?</item>
</plurals>
+ <plurals name="permission_progress_delete_generic" formatted="false" msgid="1006212243422543162">
+ <item quantity="one">Isusa izinto ezingu-<xliff:g id="COUNT">^1</xliff:g>…</item>
+ <item quantity="other">Isusa izinto ezingu-<xliff:g id="COUNT">^1</xliff:g>…</item>
+ </plurals>
+ <string name="transcode_denied" msgid="6760546817138288976">"I-<xliff:g id="APP_NAME">%s</xliff:g> ayikwazi ukucubungula amafayela emidiya"</string>
+ <string name="transcode_processing_cancelled" msgid="5340383917746945590">"Ukucubungula imidiya kukhanseliwe"</string>
+ <string name="transcode_processing_error" msgid="8921643164508407874">"Iphutha lokucubungula imidiya"</string>
+ <string name="transcode_processing_success" msgid="447288876429730122">"Ukucubungula imidiya kuphumelele"</string>
+ <string name="transcode_processing_started" msgid="7789086308155361523">"Ukucubungula imidiya kuqalile"</string>
+ <string name="transcode_processing" msgid="6753136468864077258">"Icubungula imidiya…"</string>
+ <string name="transcode_cancel" msgid="8555752601907598192">"Khansela"</string>
+ <string name="transcode_wait" msgid="8909773149560697501">"Linda"</string>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d6171ca..98c885b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -88,21 +88,41 @@
<item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to modify this audio file?</item>
<item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to modify <xliff:g id="count" example="42">^2</xliff:g> audio files?</item>
</plurals>
+ <!-- Progress dialog message after user allows write permission to the audio item [CHAR LIMIT=128] -->
+ <plurals name="permission_progress_write_audio">
+ <item quantity="one">Modifying audio file…</item>
+ <item quantity="other">Modifying <xliff:g id="count" example="42">^1</xliff:g> audio files…</item>
+ </plurals>
<!-- Dialog title asking if user will allow write permission to the video item displayed below this string. [CHAR LIMIT=128] -->
<plurals name="permission_write_video">
<item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to modify this video?</item>
<item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to modify <xliff:g id="count" example="42">^2</xliff:g> videos?</item>
</plurals>
+ <!-- Progress dialog message after user allows write permission to the video item [CHAR LIMIT=128] -->
+ <plurals name="permission_progress_write_video">
+ <item quantity="one">Modifying video…</item>
+ <item quantity="other">Modifying <xliff:g id="count" example="42">^1</xliff:g> videos…</item>
+ </plurals>
<!-- Dialog title asking if user will allow write permission to the image item displayed below this string. [CHAR LIMIT=128] -->
<plurals name="permission_write_image">
<item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to modify this photo?</item>
<item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to modify <xliff:g id="count" example="42">^2</xliff:g> photos?</item>
</plurals>
+ <!-- Progress dialog message after user allows write permission to the image item [CHAR LIMIT=128] -->
+ <plurals name="permission_progress_write_image">
+ <item quantity="one">Modifying photo…</item>
+ <item quantity="other">Modifying <xliff:g id="count" example="42">^1</xliff:g> photos…</item>
+ </plurals>
<!-- Dialog title asking if user will allow write permission to the generic item displayed below this string. [CHAR LIMIT=128] -->
<plurals name="permission_write_generic">
<item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to modify this item?</item>
<item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to modify <xliff:g id="count" example="42">^2</xliff:g> items?</item>
</plurals>
+ <!-- Progress dialog message after user allows write permission to the generic item [CHAR LIMIT=128] -->
+ <plurals name="permission_progress_write_generic">
+ <item quantity="one">Modifying item…</item>
+ <item quantity="other">Modifying <xliff:g id="count" example="42">^1</xliff:g> items…</item>
+ </plurals>
<!-- ========================= TRASH STRINGS ========================= -->
@@ -111,21 +131,41 @@
<item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move this audio file to trash?</item>
<item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move <xliff:g id="count" example="42">^2</xliff:g> audio files to trash?</item>
</plurals>
+ <!-- Progress dialog message after user allows trash permission to the audio item [CHAR LIMIT=128] -->
+ <plurals name="permission_progress_trash_audio">
+ <item quantity="one">Moving audio file to trash…</item>
+ <item quantity="other">Moving <xliff:g id="count" example="42">^1</xliff:g> audio files to trash…</item>
+ </plurals>
<!-- Dialog title asking if user will allow trash permission to the video item displayed below this string. [CHAR LIMIT=128] -->
<plurals name="permission_trash_video">
<item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move this video to trash?</item>
<item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move <xliff:g id="count" example="42">^2</xliff:g> videos to trash?</item>
</plurals>
+ <!-- Progress dialog message after user allows trash permission to the video item [CHAR LIMIT=128] -->
+ <plurals name="permission_progress_trash_video">
+ <item quantity="one">Moving video to trash…</item>
+ <item quantity="other">Moving <xliff:g id="count" example="42">^1</xliff:g> videos to trash…</item>
+ </plurals>
<!-- Dialog title asking if user will allow trash permission to the image item displayed below this string. [CHAR LIMIT=128] -->
<plurals name="permission_trash_image">
<item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move this photo to trash?</item>
<item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move <xliff:g id="count" example="42">^2</xliff:g> photos to trash?</item>
</plurals>
+ <!-- Progress dialog message after user allows trash permission to the image item [CHAR LIMIT=128] -->
+ <plurals name="permission_progress_trash_image">
+ <item quantity="one">Moving photo to trash…</item>
+ <item quantity="other">Moving <xliff:g id="count" example="42">^1</xliff:g> photos to trash…</item>
+ </plurals>
<!-- Dialog title asking if user will allow trash permission to the generic item displayed below this string. [CHAR LIMIT=128] -->
<plurals name="permission_trash_generic">
<item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move this item to trash?</item>
<item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move <xliff:g id="count" example="42">^2</xliff:g> items to trash?</item>
</plurals>
+ <!-- Progress dialog message after user allows trash permission to the generic item [CHAR LIMIT=128] -->
+ <plurals name="permission_progress_trash_generic">
+ <item quantity="one">Moving item to trash…</item>
+ <item quantity="other">Moving <xliff:g id="count" example="42">^1</xliff:g> items to trash…</item>
+ </plurals>
<!-- ========================= UNTRASH STRINGS ========================= -->
@@ -134,21 +174,41 @@
<item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move this audio file out of trash?</item>
<item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move <xliff:g id="count" example="42">^2</xliff:g> audio files out of trash?</item>
</plurals>
+ <!-- Progress dialog message after user allows untrash permission to the audio item [CHAR LIMIT=128] -->
+ <plurals name="permission_progress_untrash_audio">
+ <item quantity="one">Moving audio file out of trash…</item>
+ <item quantity="other">Moving <xliff:g id="count" example="42">^1</xliff:g> audio files out of trash…</item>
+ </plurals>
<!-- Dialog title asking if user will allow untrash permission to the video item displayed below this string. [CHAR LIMIT=128] -->
<plurals name="permission_untrash_video">
<item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move this video out of trash?</item>
<item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move <xliff:g id="count" example="42">^2</xliff:g> videos out of trash?</item>
</plurals>
+ <!-- Progress dialog message after user allows untrash permission to the video item [CHAR LIMIT=128] -->
+ <plurals name="permission_progress_untrash_video">
+ <item quantity="one">Moving video out of trash…</item>
+ <item quantity="other">Moving <xliff:g id="count" example="42">^1</xliff:g> videos out of trash…</item>
+ </plurals>
<!-- Dialog title asking if user will allow untrash permission to the image item displayed below this string. [CHAR LIMIT=128] -->
<plurals name="permission_untrash_image">
<item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move this photo out of trash?</item>
<item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move <xliff:g id="count" example="42">^2</xliff:g> photos out of trash?</item>
</plurals>
+ <!-- Progress dialog message after user allows untrash permission to the image item [CHAR LIMIT=128] -->
+ <plurals name="permission_progress_untrash_image">
+ <item quantity="one">Moving photo out of trash…</item>
+ <item quantity="other">Moving <xliff:g id="count" example="42">^1</xliff:g> photos out of trash…</item>
+ </plurals>
<!-- Dialog title asking if user will allow untrash permission to the generic item displayed below this string. [CHAR LIMIT=128] -->
<plurals name="permission_untrash_generic">
<item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move this item out of trash?</item>
<item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move <xliff:g id="count" example="42">^2</xliff:g> items out of trash?</item>
</plurals>
+ <!-- Progress dialog message after user allows untrash permission to the generic item [CHAR LIMIT=128] -->
+ <plurals name="permission_progress_untrash_generic">
+ <item quantity="one">Moving item out of trash…</item>
+ <item quantity="other">Moving <xliff:g id="count" example="42">^1</xliff:g> items out of trash…</item>
+ </plurals>
<!-- ========================= DELETE STRINGS ========================= -->
@@ -157,22 +217,67 @@
<item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to delete this audio file?</item>
<item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to delete <xliff:g id="count" example="42">^2</xliff:g> audio files?</item>
</plurals>
+ <!-- Progress dialog message after user allows delete permission to the audio item [CHAR LIMIT=128] -->
+ <plurals name="permission_progress_delete_audio">
+ <item quantity="one">Deleting audio file…</item>
+ <item quantity="other">Deleting <xliff:g id="count" example="42">^1</xliff:g> audio files…</item>
+ </plurals>
<!-- Dialog title asking if user will allow delete permission to the video item displayed below this string. [CHAR LIMIT=128] -->
<plurals name="permission_delete_video">
<item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to delete this video?</item>
<item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to delete <xliff:g id="count" example="42">^2</xliff:g> videos?</item>
</plurals>
+ <!-- Progress dialog message after user allows delete permission to the video item [CHAR LIMIT=128] -->
+ <plurals name="permission_progress_delete_video">
+ <item quantity="one">Deleting video…</item>
+ <item quantity="other">Deleting <xliff:g id="count" example="42">^1</xliff:g> videos…</item>
+ </plurals>
<!-- Dialog title asking if user will allow delete permission to the image item displayed below this string. [CHAR LIMIT=128] -->
<plurals name="permission_delete_image">
<item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to delete this photo?</item>
<item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to delete <xliff:g id="count" example="42">^2</xliff:g> photos?</item>
</plurals>
+ <!-- Progress dialog message after user allows delete permission to the image item [CHAR LIMIT=128] -->
+ <plurals name="permission_progress_delete_image">
+ <item quantity="one">Deleting photo…</item>
+ <item quantity="other">Deleting <xliff:g id="count" example="42">^1</xliff:g> photos…</item>
+ </plurals>
<!-- Dialog title asking if user will allow delete permission to the generic item displayed below this string. [CHAR LIMIT=128] -->
<plurals name="permission_delete_generic">
<item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to delete this item?</item>
<item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to delete <xliff:g id="count" example="42">^2</xliff:g> items?</item>
</plurals>
+ <!-- Progress dialog message after user allows delete permission to the generic item [CHAR LIMIT=128] -->
+ <plurals name="permission_progress_delete_generic">
+ <item quantity="one">Deleting item…</item>
+ <item quantity="other">Deleting <xliff:g id="count" example="42">^1</xliff:g> items…</item>
+ </plurals>
<!-- ========================= END AUTO-GENERATED BY gen_strings.py ========================= -->
+ <!-- ========================= TRANSCODE STRINGS ========================= -->
+
+ <!-- Transcode denied toast text. [CHAR LIMIT=NONE] -->
+ <string name="transcode_denied"><xliff:g id="app_name" example="File manager">%s</xliff:g> can\'t process media files</string>
+
+ <!-- Transcode cancelled notification. -->
+ <string name="transcode_processing_cancelled">Media processing cancelled</string>
+
+ <!-- Transcode error notification. -->
+ <string name="transcode_processing_error">Media processing error</string>
+
+ <!-- Transcode success notification. -->
+ <string name="transcode_processing_success">Media processing success</string>
+
+ <!-- Transcode started notification. -->
+ <string name="transcode_processing_started">Media processing started</string>
+
+ <!-- Transcode processing notification. -->
+ <string name="transcode_processing">Processing media…</string>
+
+ <!-- Transcode intermediate ANR dialog cancel button. -->
+ <string name="transcode_cancel">Cancel</string>
+
+ <!-- Transcode intermediate ANR dialog wait button. -->
+ <string name="transcode_wait">Wait</string>
</resources>
diff --git a/sqlite3.sh b/sqlite3.sh
index 7f7780b..cf9b4a5 100644
--- a/sqlite3.sh
+++ b/sqlite3.sh
@@ -59,6 +59,26 @@
adb shell am force-stop $package
}
+function get-id-from-data () {
+ adb root
+ path="$1"
+ package=$(get-package)
+ dir="/data/user/0/$package/databases/external.db"
+ clause="\"select _id from files where _data='$path';\""
+ echo $clause
+ adb shell sqlite3 $dir $clause
+}
+
+function get-data-from-id () {
+ adb root
+ _id="$1"
+ package=$(get-package)
+ dir="/data/user/0/$package/databases/external.db"
+ clause="\"select _data from files where _id='$_id';\""
+ echo $clause
+ adb shell sqlite3 $dir $clause
+}
+
function get-package() {
if [ -z "$(adb shell pm list package com.android.providers.media.module)" ]
then
diff --git a/src/com/android/providers/media/DatabaseHelper.java b/src/com/android/providers/media/DatabaseHelper.java
index 9c67aa6..7bcdf62 100644
--- a/src/com/android/providers/media/DatabaseHelper.java
+++ b/src/com/android/providers/media/DatabaseHelper.java
@@ -39,6 +39,7 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
+import android.os.UserHandle;
import android.provider.MediaStore;
import android.provider.MediaStore.Audio;
import android.provider.MediaStore.Downloads;
@@ -428,7 +429,7 @@
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
- mProjectionMapCache.put(clazz, map);
+ mProjectionMapCache.put(clazz, map);
}
result.putAll(map);
}
@@ -813,7 +814,9 @@
+ "scene_capture_type INTEGER DEFAULT NULL, generation_added INTEGER DEFAULT 0,"
+ "generation_modified INTEGER DEFAULT 0, xmp BLOB DEFAULT NULL,"
+ "_transcode_status INTEGER DEFAULT 0, _video_codec_type TEXT DEFAULT NULL,"
- + "_modifier INTEGER DEFAULT 0)");
+ + "_modifier INTEGER DEFAULT 0, is_recording INTEGER DEFAULT 0,"
+ + "redacted_uri_id TEXT DEFAULT NULL, _user_id INTEGER DEFAULT "
+ + UserHandle.myUserId() + ")");
db.execSQL("CREATE TABLE log (time DATETIME, message TEXT)");
if (!mInternal) {
@@ -864,7 +867,9 @@
db.beginTransaction();
Log.d(TAG, "Starting migration from legacy provider");
- mMigrationListener.onStarted(client, mVolumeName);
+ if (mMigrationListener != null) {
+ mMigrationListener.onStarted(client, mVolumeName);
+ }
try (Cursor c = client.query(queryUri, sMigrateColumns.toArray(new String[0]),
extras, null)) {
final ContentValues values = new ContentValues();
@@ -957,7 +962,9 @@
final int progress = c.getPosition();
final int total = c.getCount();
Log.v(TAG, "Migrated " + progress + " of " + total + "...");
- mMigrationListener.onProgress(client, mVolumeName, progress, total);
+ if (mMigrationListener != null) {
+ mMigrationListener.onProgress(client, mVolumeName, progress, total);
+ }
}
}
@@ -972,7 +979,9 @@
// only have one possible shot, so mark everything successful
db.setTransactionSuccessful();
db.endTransaction();
- mMigrationListener.onFinished(client, mVolumeName);
+ if (mMigrationListener != null) {
+ mMigrationListener.onFinished(client, mVolumeName);
+ }
}
}
@@ -1169,7 +1178,7 @@
if (!internal) {
db.execSQL("CREATE VIEW audio_playlists AS SELECT "
- + String.join(",", getProjectionMap(Audio.Playlists.class).keySet())
+ + getColumnsForCollection(Audio.Playlists.class)
+ " FROM files WHERE media_type=4");
}
@@ -1193,16 +1202,16 @@
+ "3 AS grouporder FROM searchhelpertitle WHERE (title != '')");
db.execSQL("CREATE VIEW audio AS SELECT "
- + String.join(",", getProjectionMap(Audio.Media.class).keySet())
+ + getColumnsForCollection(Audio.Media.class)
+ " FROM files WHERE media_type=2");
db.execSQL("CREATE VIEW video AS SELECT "
- + String.join(",", getProjectionMap(Video.Media.class).keySet())
+ + getColumnsForCollection(Video.Media.class)
+ " FROM files WHERE media_type=3");
db.execSQL("CREATE VIEW images AS SELECT "
- + String.join(",", getProjectionMap(Images.Media.class).keySet())
+ + getColumnsForCollection(Images.Media.class)
+ " FROM files WHERE media_type=1");
db.execSQL("CREATE VIEW downloads AS SELECT "
- + String.join(",", getProjectionMap(Downloads.class).keySet())
+ + getColumnsForCollection(Downloads.class)
+ " FROM files WHERE is_download=1");
db.execSQL("CREATE VIEW audio_artists AS SELECT "
@@ -1216,6 +1225,25 @@
+ " AND volume_name IN " + filterVolumeNames
+ " GROUP BY artist_id");
+ db.execSQL("CREATE VIEW audio_artists_albums AS SELECT "
+ + " album_id AS " + Audio.Albums._ID
+ + ", album_id AS " + Audio.Albums.ALBUM_ID
+ + ", MIN(album) AS " + Audio.Albums.ALBUM
+ + ", album_key AS " + Audio.Albums.ALBUM_KEY
+ + ", artist_id AS " + Audio.Albums.ARTIST_ID
+ + ", artist AS " + Audio.Albums.ARTIST
+ + ", artist_key AS " + Audio.Albums.ARTIST_KEY
+ + ", (SELECT COUNT(*) FROM audio WHERE " + Audio.Albums.ALBUM_ID
+ + " = TEMP.album_id) AS " + Audio.Albums.NUMBER_OF_SONGS
+ + ", COUNT(DISTINCT _id) AS " + Audio.Albums.NUMBER_OF_SONGS_FOR_ARTIST
+ + ", MIN(year) AS " + Audio.Albums.FIRST_YEAR
+ + ", MAX(year) AS " + Audio.Albums.LAST_YEAR
+ + ", NULL AS " + Audio.Albums.ALBUM_ART
+ + " FROM audio TEMP"
+ + " WHERE is_music=1 AND is_pending=0 AND is_trashed=0"
+ + " AND volume_name IN " + filterVolumeNames
+ + " GROUP BY album_id, artist_id");
+
db.execSQL("CREATE VIEW audio_albums AS SELECT "
+ " album_id AS " + Audio.Albums._ID
+ ", album_id AS " + Audio.Albums.ALBUM_ID
@@ -1242,6 +1270,10 @@
+ " GROUP BY genre_id");
}
+ private String getColumnsForCollection(Class<?> collection) {
+ return String.join(",", getProjectionMap(collection).keySet()) + ",_modifier";
+ }
+
private static void makePristineTriggers(SQLiteDatabase db) {
// drop all triggers
Cursor c = db.query("sqlite_master", new String[] {"name"}, "type is 'trigger'",
@@ -1372,6 +1404,16 @@
db.execSQL("ALTER TABLE files ADD COLUMN is_audiobook INTEGER DEFAULT 0;");
}
+ private static void updateAddRecording(SQLiteDatabase db, boolean internal) {
+ db.execSQL("ALTER TABLE files ADD COLUMN is_recording INTEGER DEFAULT 0;");
+ // We add the column is_recording, rescan all music files
+ db.execSQL("UPDATE files SET date_modified=0 WHERE is_music=1;");
+ }
+
+ private static void updateAddRedactedUriId(SQLiteDatabase db) {
+ db.execSQL("ALTER TABLE files ADD COLUMN redacted_uri_id TEXT DEFAULT NULL;");
+ }
+
private static void updateClearLocation(SQLiteDatabase db, boolean internal) {
db.execSQL("UPDATE files SET latitude=NULL, longitude=NULL;");
}
@@ -1425,6 +1467,7 @@
db.execSQL("ALTER TABLE files ADD COLUMN _transcode_status INTEGER DEFAULT 0;");
}
+
private static void updateAddVideoCodecType(SQLiteDatabase db, boolean internal) {
db.execSQL("ALTER TABLE files ADD COLUMN _video_codec_type TEXT DEFAULT NULL;");
}
@@ -1514,6 +1557,11 @@
db.execSQL("UPDATE files SET _modifier=3;");
}
+ private void updateUserId(SQLiteDatabase db) {
+ db.execSQL(String.format("ALTER TABLE files ADD COLUMN _user_id INTEGER DEFAULT %d;",
+ UserHandle.myUserId()));
+ }
+
private static void recomputeDataValues(SQLiteDatabase db, boolean internal) {
try (Cursor c = db.query("files", new String[] { FileColumns._ID, FileColumns.DATA },
null, null, null, null, null, null)) {
@@ -1545,9 +1593,7 @@
Log.d(TAG, "Recomputing " + c.getCount() + " MediaType values");
// Accumulate all the new MEDIA_TYPE updates.
- final ContentValues values = new ContentValues();
while (c.moveToNext()) {
- values.clear();
final long id = c.getLong(0);
final String mimeType = c.getString(1);
// Only update Document and Subtitle media type
@@ -1578,7 +1624,7 @@
static final int VERSION_R = 1115;
// Leave some gaps in database version tagging to allow R schema changes
// to go independent of S schema changes.
- static final int VERSION_S = 1204;
+ static final int VERSION_S = 1209;
static final int VERSION_LATEST = VERSION_S;
/**
@@ -1739,6 +1785,21 @@
if (fromVersion < 1204) {
// Empty version bump to ensure views are recreated
}
+ if (fromVersion < 1205) {
+ updateAddRecording(db, internal);
+ }
+ if (fromVersion < 1206) {
+ // Empty version bump to ensure views are recreated
+ }
+ if (fromVersion < 1207) {
+ updateAddRedactedUriId(db);
+ }
+ if (fromVersion < 1208) {
+ updateUserId(db);
+ }
+ if (fromVersion < 1209) {
+ // Empty version bump to ensure views are recreated
+ }
// If this is the legacy database, it's not worth recomputing data
// values locally, since they'll be recomputed after the migration
diff --git a/src/com/android/providers/media/FileLookupResult.java b/src/com/android/providers/media/FileLookupResult.java
new file mode 100644
index 0000000..f0e6bfb
--- /dev/null
+++ b/src/com/android/providers/media/FileLookupResult.java
@@ -0,0 +1,40 @@
+/*
+ * 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;
+
+/**
+ * Wrapper class which contains transforms, transforms completion status and ioPath for transform
+ * lookup query for a file and uid pair.
+ */
+public final class FileLookupResult {
+ public final int transforms;
+ public final int transformsReason;
+ public final int uid;
+ public final boolean transformsComplete;
+ public final boolean transformsSupported;
+ public final String ioPath;
+
+ public FileLookupResult(int transforms, int transformsReason, int uid,
+ boolean transformsComplete, boolean transformsSupported, String ioPath) {
+ this.transforms = transforms;
+ this.transformsReason = transformsReason;
+ this.uid = uid;
+ this.transformsComplete = transformsComplete;
+ this.transformsSupported = transformsSupported;
+ this.ioPath = ioPath;
+ }
+}
diff --git a/src/com/android/providers/media/FileOpenResult.java b/src/com/android/providers/media/FileOpenResult.java
new file mode 100644
index 0000000..1052f98
--- /dev/null
+++ b/src/com/android/providers/media/FileOpenResult.java
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+/**
+ * Wrapper class which contains the result of an open.
+ */
+public final class FileOpenResult {
+ public final int status;
+ public final int uid;
+ public final int transformsUid;
+ public final long[] redactionRanges;
+
+ public FileOpenResult(int status, int uid, int transformsUid, long[] redactionRanges) {
+ this.status = status;
+ this.uid = uid;
+ this.transformsUid = transformsUid;
+ this.redactionRanges = redactionRanges;
+ }
+}
diff --git a/src/com/android/providers/media/LocalCallingIdentity.java b/src/com/android/providers/media/LocalCallingIdentity.java
index 393ee50..77a4c6b 100644
--- a/src/com/android/providers/media/LocalCallingIdentity.java
+++ b/src/com/android/providers/media/LocalCallingIdentity.java
@@ -17,6 +17,7 @@
package com.android.providers.media;
import static android.Manifest.permission.ACCESS_MEDIA_LOCATION;
+import static android.Manifest.permission.MANAGE_EXTERNAL_STORAGE;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.permissionToOp;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
@@ -42,6 +43,9 @@
import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
+import android.compat.annotation.EnabledSince;
import android.content.ContentProvider;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -57,13 +61,16 @@
import androidx.annotation.GuardedBy;
import androidx.annotation.NonNull;
+import com.android.modules.utils.build.SdkLevel;
import com.android.providers.media.util.LongArray;
+import com.android.providers.media.util.UserCache;
import java.util.Locale;
public class LocalCallingIdentity {
public final int pid;
public final int uid;
+ private final UserHandle user;
private final Context context;
private final String packageNameUnchecked;
// Info used for logging permission checks
@@ -72,9 +79,16 @@
private LocalCallingIdentity(Context context, int pid, int uid, String packageNameUnchecked,
@Nullable String attributionTag) {
+ this(context, pid, uid, UserHandle.getUserHandleForUid(uid), packageNameUnchecked,
+ attributionTag);
+ }
+
+ private LocalCallingIdentity(Context context, int pid, int uid, UserHandle user,
+ String packageNameUnchecked, @Nullable String attributionTag) {
this.context = context;
this.pid = pid;
this.uid = uid;
+ this.user = user;
this.packageNameUnchecked = packageNameUnchecked;
this.attributionTag = attributionTag;
}
@@ -91,7 +105,8 @@
private static final long UNKNOWN_ROW_ID = -1;
- public static LocalCallingIdentity fromBinder(Context context, ContentProvider provider) {
+ public static LocalCallingIdentity fromBinder(Context context, ContentProvider provider,
+ UserCache userCache) {
String callingPackage = provider.getCallingPackageUnchecked();
int binderUid = Binder.getCallingUid();
if (callingPackage == null) {
@@ -107,8 +122,27 @@
if (callingAttributionTag == null) {
callingAttributionTag = context.getAttributionTag();
}
+ UserHandle user;
+ if (binderUid == Process.SHELL_UID || binderUid == Process.ROOT_UID) {
+ // For requests coming from the shell (eg `content query`), assume they are
+ // for the user we are running as.
+ user = Process.myUserHandle();
+ } else {
+ user = UserHandle.getUserHandleForUid(binderUid);
+ }
+ // We need to use the cached variant here, because the uncached version may
+ // make a binder transaction, which would cause infinite recursion here.
+ // Using the cached variant is fine, because we shouldn't be getting any binder
+ // requests for this volume before it has been mounted anyway, at which point
+ // we must already know about the new user.
+ if (!userCache.userSharesMediaWithParentCached(user)) {
+ // It's possible that we got a cross-profile intent from a regular work profile; in
+ // that case, the request was explicitly targeted at the media database of the owner
+ // user; reflect that here.
+ user = Process.myUserHandle();
+ }
return new LocalCallingIdentity(context, Binder.getCallingPid(), binderUid,
- callingPackage, callingAttributionTag);
+ user, callingPackage, callingAttributionTag);
}
public static LocalCallingIdentity fromExternal(Context context, int uid) {
@@ -126,6 +160,7 @@
ident.hasPermissionResolved = PERMISSION_IS_REDACTION_NEEDED;
}
}
+
return ident;
}
@@ -135,10 +170,15 @@
}
public static LocalCallingIdentity fromSelf(Context context) {
+ return fromSelfAsUser(context, Process.myUserHandle());
+ }
+
+ public static LocalCallingIdentity fromSelfAsUser(Context context, UserHandle user) {
final LocalCallingIdentity ident = new LocalCallingIdentity(
context,
android.os.Process.myPid(),
android.os.Process.myUid(),
+ user,
context.getOpPackageName(),
context.getAttributionTag());
@@ -147,6 +187,8 @@
// Use ident.attributionTag from context, hence no change
ident.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
ident.targetSdkVersionResolved = true;
+ ident.shouldBypass = false;
+ ident.shouldBypassResolved = true;
ident.hasPermission = ~(PERMISSION_IS_LEGACY_GRANTED | PERMISSION_IS_LEGACY_WRITE
| PERMISSION_IS_LEGACY_READ | PERMISSION_IS_REDACTION_NEEDED
| PERMISSION_IS_SHELL | PERMISSION_IS_DELEGATOR);
@@ -211,6 +253,10 @@
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
+ public UserHandle getUser() {
+ return user;
+ }
+
public static final int PERMISSION_IS_SELF = 1 << 0;
public static final int PERMISSION_IS_SHELL = 1 << 1;
public static final int PERMISSION_IS_MANAGER = 1 << 2;
@@ -335,7 +381,84 @@
return true;
}
- return checkIsLegacyStorageGranted(context, uid, getPackageName());
+ return checkIsLegacyStorageGranted(context, uid, getPackageName(), attributionTag);
+ }
+
+ private volatile boolean shouldBypass;
+ private volatile boolean shouldBypassResolved;
+
+ /**
+ * Allow apps holding {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE}
+ * permission to request raw external storage access.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
+ static final long ENABLE_RAW_MANAGE_EXTERNAL_STORAGE_ACCESS = 178209446L;
+
+ /**
+ * Allow apps holding {@link android.app.role}#SYSTEM_GALLERY role to request raw external
+ * storage access.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.R)
+ static final long ENABLE_RAW_SYSTEM_GALLERY_ACCESS = 183372781L;
+
+ /**
+ * Checks if app chooses to bypass database operations.
+ *
+ * <p>
+ * Note that this method doesn't check if app qualifies to bypass database operations.
+ *
+ * @return {@code true} if AndroidManifest.xml of this app has
+ * android:requestRawExternalStorageAccess=true
+ * {@code false} otherwise.
+ */
+ public boolean shouldBypassDatabase(boolean isSystemGallery) {
+ if (!shouldBypassResolved) {
+ shouldBypass = shouldBypassDatabaseInternal(isSystemGallery);
+ shouldBypassResolved = true;
+ }
+ return shouldBypass;
+ }
+
+ private boolean shouldBypassDatabaseInternal(boolean isSystemGallery) {
+ if (!SdkLevel.isAtLeastS()) {
+ // We need to parse the manifest flag ourselves here.
+ // TODO(b/178209446): Parse app manifest to get new flag values
+ return true;
+ }
+
+ final ApplicationInfo ai;
+ try {
+ ai = context.getPackageManager()
+ .getApplicationInfo(getPackageName(), 0);
+ if (ai != null) {
+ final int requestRawExternalStorageValue
+ = ai.getRequestRawExternalStorageAccess();
+ if (requestRawExternalStorageValue
+ != ApplicationInfo.RAW_EXTERNAL_STORAGE_ACCESS_DEFAULT) {
+ return requestRawExternalStorageValue
+ == ApplicationInfo.RAW_EXTERNAL_STORAGE_ACCESS_REQUESTED;
+ }
+ // Manifest flag is not set, hence return default value based on the category of the
+ // app and targetSDK.
+ if (isSystemGallery) {
+ if (CompatChanges.isChangeEnabled(
+ ENABLE_RAW_SYSTEM_GALLERY_ACCESS, uid)) {
+ // If systemGallery, then the flag will default to false when they are
+ // targeting targetSDK>=30.
+ return false;
+ }
+ } else if (CompatChanges.isChangeEnabled(
+ ENABLE_RAW_MANAGE_EXTERNAL_STORAGE_ACCESS, uid)) {
+ // If app has MANAGE_EXTERNAL_STORAGE, the flag will default to false when they
+ // are targeting targetSDK>=31.
+ return false;
+ }
+ }
+ } catch (NameNotFoundException e) {
+ }
+ return true;
}
private boolean isScopedStorageEnforced(boolean defaultScopedStorage,
@@ -424,4 +547,20 @@
return rowIdOfDeletedPaths.getOrDefault(path.toLowerCase(Locale.ROOT), UNKNOWN_ROW_ID);
}
}
+
+ private volatile int applicationMediaCapabilitiesSupportedFlags = -1;
+ private volatile int applicationMediaCapabilitiesUnsupportedFlags = -1;
+
+ public int getApplicationMediaCapabilitiesSupportedFlags() {
+ return applicationMediaCapabilitiesSupportedFlags;
+ }
+
+ public int getApplicationMediaCapabilitiesUnsupportedFlags() {
+ return applicationMediaCapabilitiesUnsupportedFlags;
+ }
+
+ public void setApplicationMediaCapabilitiesFlags(int supportedFlags, int unsupportedFlags) {
+ applicationMediaCapabilitiesSupportedFlags = supportedFlags;
+ applicationMediaCapabilitiesUnsupportedFlags = unsupportedFlags;
+ }
}
diff --git a/src/com/android/providers/media/MediaDocumentsProvider.java b/src/com/android/providers/media/MediaDocumentsProvider.java
index 222b9ea..c958721 100644
--- a/src/com/android/providers/media/MediaDocumentsProvider.java
+++ b/src/com/android/providers/media/MediaDocumentsProvider.java
@@ -23,6 +23,7 @@
import static android.provider.DocumentsContract.QUERY_ARG_FILE_SIZE_OVER;
import static android.provider.DocumentsContract.QUERY_ARG_LAST_MODIFIED_AFTER;
import static android.provider.DocumentsContract.QUERY_ARG_MIME_TYPES;
+import static android.provider.MediaStore.GET_MEDIA_URI_CALL;
import android.content.ContentResolver;
import android.content.ContentUris;
@@ -71,6 +72,7 @@
import com.android.providers.media.util.FileUtils;
import java.io.FileNotFoundException;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -430,6 +432,28 @@
}
@Override
+ public Bundle call(String method, String arg, Bundle extras) {
+ Bundle bundle = super.call(method, arg, extras);
+ if (bundle == null && !TextUtils.isEmpty(method)) {
+ switch (method) {
+ case GET_MEDIA_URI_CALL: {
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.WRITE_MEDIA_STORAGE, TAG);
+ final Uri documentUri = extras.getParcelable(MediaStore.EXTRA_URI);
+ final String docId = DocumentsContract.getDocumentId(documentUri);
+ final Bundle out = new Bundle();
+ final Uri uri = getUriForDocumentId(docId);
+ out.putParcelable(MediaStore.EXTRA_URI, uri);
+ return out;
+ }
+ default:
+ Log.w(TAG, "unknown method passed to call(): " + method);
+ }
+ }
+ return bundle;
+ }
+
+ @Override
public void deleteDocument(String docId) throws FileNotFoundException {
enforceShellRestrictions();
final Uri target = getUriForDocumentId(docId);
@@ -1018,6 +1042,7 @@
throws FileNotFoundException {
enforceShellRestrictions();
final Uri target = getUriForDocumentId(docId);
+ final int callingUid = Binder.getCallingUid();
if (!"r".equals(mode)) {
throw new IllegalArgumentException("Media is read-only");
@@ -1026,12 +1051,27 @@
// Delegate to real provider
final long token = Binder.clearCallingIdentity();
try {
- return getContext().getContentResolver().openFileDescriptor(target, mode);
+ return openFileForRead(target, callingUid);
} finally {
Binder.restoreCallingIdentity(token);
}
}
+ public ParcelFileDescriptor openFileForRead(final Uri target, final int callingUid)
+ throws FileNotFoundException {
+ final Bundle opts = new Bundle();
+ opts.putInt(MediaStore.EXTRA_MEDIA_CAPABILITIES_UID, callingUid);
+
+ AssetFileDescriptor afd =
+ getContext().getContentResolver().openTypedAssetFileDescriptor(target, "*/*",
+ opts);
+ if (afd == null) {
+ return null;
+ }
+
+ return afd.getParcelFileDescriptor();
+ }
+
@Override
public AssetFileDescriptor openDocumentThumbnail(
String docId, Point sizeHint, CancellationSignal signal) throws FileNotFoundException {
diff --git a/src/com/android/providers/media/MediaProvider.java b/src/com/android/providers/media/MediaProvider.java
index 7156f55..b29b3d7 100644
--- a/src/com/android/providers/media/MediaProvider.java
+++ b/src/com/android/providers/media/MediaProvider.java
@@ -27,15 +27,18 @@
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.database.Cursor.FIELD_TYPE_BLOB;
import static android.provider.MediaStore.MATCH_DEFAULT;
import static android.provider.MediaStore.MATCH_EXCLUDE;
import static android.provider.MediaStore.MATCH_INCLUDE;
import static android.provider.MediaStore.MATCH_ONLY;
+import static android.provider.MediaStore.QUERY_ARG_DEFER_SCAN;
import static android.provider.MediaStore.QUERY_ARG_MATCH_FAVORITE;
import static android.provider.MediaStore.QUERY_ARG_MATCH_PENDING;
import static android.provider.MediaStore.QUERY_ARG_MATCH_TRASHED;
import static android.provider.MediaStore.QUERY_ARG_RELATED_URI;
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;
@@ -64,6 +67,7 @@
import static com.android.providers.media.util.FileUtils.DEFAULT_FOLDER_NAMES;
import static com.android.providers.media.util.FileUtils.PATTERN_PENDING_FILEPATH_FOR_SQL;
import static com.android.providers.media.util.FileUtils.extractDisplayName;
+import static com.android.providers.media.util.FileUtils.extractFileExtension;
import static com.android.providers.media.util.FileUtils.extractFileName;
import static com.android.providers.media.util.FileUtils.extractPathOwnerPackageName;
import static com.android.providers.media.util.FileUtils.extractRelativePath;
@@ -73,8 +77,8 @@
import static com.android.providers.media.util.FileUtils.extractVolumePath;
import static com.android.providers.media.util.FileUtils.getAbsoluteSanitizedPath;
import static com.android.providers.media.util.FileUtils.isDataOrObbPath;
-import static com.android.providers.media.util.FileUtils.isObbOrChildPath;
import static com.android.providers.media.util.FileUtils.isDownload;
+import static com.android.providers.media.util.FileUtils.isObbOrChildPath;
import static com.android.providers.media.util.FileUtils.sanitizePath;
import static com.android.providers.media.util.Logging.LOGV;
import static com.android.providers.media.util.Logging.TAG;
@@ -87,6 +91,9 @@
import android.app.RecoverableSecurityException;
import android.app.RemoteAction;
import android.app.admin.DevicePolicyManager;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
import android.content.BroadcastReceiver;
import android.content.ClipData;
import android.content.ClipDescription;
@@ -133,17 +140,23 @@
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.ParcelFileDescriptor.OnCloseListener;
+import android.os.Parcelable;
+import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
+import android.os.UserManager;
import android.os.storage.StorageManager;
import android.os.storage.StorageManager.StorageVolumeCallback;
import android.os.storage.StorageVolume;
import android.preference.PreferenceManager;
import android.provider.BaseColumns;
import android.provider.Column;
+import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.OnPropertiesChangedListener;
+import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.provider.MediaStore.Audio;
import android.provider.MediaStore.Audio.AudioColumns;
@@ -174,13 +187,15 @@
import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
import androidx.annotation.VisibleForTesting;
+import com.android.modules.utils.build.SdkLevel;
import com.android.providers.media.DatabaseHelper.OnFilesChangeListener;
import com.android.providers.media.DatabaseHelper.OnLegacyMigrationListener;
import com.android.providers.media.fuse.ExternalStorageServiceImpl;
import com.android.providers.media.fuse.FuseDaemon;
-import com.android.providers.media.metrics.StatsdPuller;
+import com.android.providers.media.metrics.PulledMetrics;
import com.android.providers.media.playlist.Playlist;
import com.android.providers.media.scan.MediaScanner;
import com.android.providers.media.scan.ModernMediaScanner;
@@ -195,8 +210,8 @@
import com.android.providers.media.util.Metrics;
import com.android.providers.media.util.MimeUtils;
import com.android.providers.media.util.PermissionUtils;
-import com.android.providers.media.util.RedactingFileDescriptor;
import com.android.providers.media.util.SQLiteQueryBuilder;
+import com.android.providers.media.util.UserCache;
import com.android.providers.media.util.XmpInterface;
import com.google.common.hash.Hashing;
@@ -216,6 +231,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
@@ -223,6 +239,7 @@
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
+import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
@@ -237,15 +254,23 @@
*/
public class MediaProvider extends ContentProvider {
/**
+ * Enables checks to stop apps from inserting and updating to private files via media provider.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.R)
+ static final long ENABLE_CHECKS_FOR_PRIVATE_FILES = 172100307L;
+
+ /**
* Regex of a selection string that matches a specific ID.
*/
static final Pattern PATTERN_SELECTION_ID = Pattern.compile(
"(?:image_id|video_id)\\s*=\\s*(\\d+)");
- /**
- * Property that indicates whether fuse is enabled.
- */
- private static final String PROP_FUSE = "persist.sys.fuse";
+ /** File access by uid requires the transcoding transform */
+ private static final int FLAG_TRANSFORM_TRANSCODING = 1 << 0;
+
+ /** File access by uid is a synthetic path corresponding to a redacted URI */
+ private static final int FLAG_TRANSFORM_REDACTION = 1 << 1;
/**
* These directory names aren't declared in Environment as final variables, and so we need to
@@ -265,10 +290,17 @@
private static final String DIRECTORY_DCIM_LOWER_CASE = "dcim";
private static final String DIRECTORY_DOCUMENTS_LOWER_CASE = "documents";
private static final String DIRECTORY_AUDIOBOOKS_LOWER_CASE = "audiobooks";
+ private static final String DIRECTORY_RECORDINGS_LOWER_CASE = "recordings";
private static final String DIRECTORY_ANDROID_LOWER_CASE = "android";
private static final String DIRECTORY_MEDIA = "media";
private static final String DIRECTORY_THUMBNAILS = ".thumbnails";
+ private static final List<String> PRIVATE_SUBDIRECTORIES_ANDROID = Arrays.asList("data", "obb");
+ private static final String REDACTED_URI_ID_PREFIX = "RUID";
+ private static final String TRANSFORMS_SYNTHETIC_DIR = ".transforms/synthetic";
+ private static final String REDACTED_URI_DIR = TRANSFORMS_SYNTHETIC_DIR + "/redacted";
+ public static final int REDACTED_URI_ID_SIZE = 36;
+ private static final String QUERY_ARG_REDACTED_URI = "android:query-arg-redacted-uri";
/**
* Hard-coded filename where the current value of
@@ -305,8 +337,29 @@
private static final String MATCH_PENDING_FROM_FUSE = String.format("lower(%s) NOT REGEXP '%s'",
MediaColumns.DATA, PATTERN_PENDING_FILEPATH_FOR_SQL);
+ /**
+ * This flag is replaced with {@link MediaStore#QUERY_ARG_DEFER_SCAN} from S onwards and only
+ * kept around for app compatibility in R.
+ */
+ private static final String QUERY_ARG_DO_ASYNC_SCAN = "android:query-arg-do-async-scan";
+ /**
+ * Enable option to defer the scan triggered as part of MediaProvider#update()
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.R)
+ static final long ENABLE_DEFERRED_SCAN = 180326732L;
+
+ /**
+ * Enable option to include database rows of files from recently unmounted
+ * volume in MediaProvider#query
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
+ static final long ENABLE_INCLUDE_ALL_VOLUMES = 182734110L;
+
// Stolen from: UserHandle#getUserId
private static final int PER_USER_RANGE = 100000;
+ private static final int MY_UID = android.os.Process.myUid();
private static final boolean PROP_CROSS_USER_ALLOWED =
SystemProperties.getBoolean("external_storage.cross_user.enabled", false);
private static final String PROP_CROSS_USER_ROOT =
@@ -325,65 +378,32 @@
sDataColumns.put(MediaStore.Audio.AlbumColumns.ALBUM_ART, null);
}
- private static final Object sCacheLock = new Object();
-
- @GuardedBy("sCacheLock")
- private static final Set<String> sCachedExternalVolumeNames = new ArraySet<>();
- @GuardedBy("sCacheLock")
- private static final Map<String, File> sCachedVolumePaths = new ArrayMap<>();
- @GuardedBy("sCacheLock")
- private static final Map<String, Collection<File>> sCachedVolumeScanPaths = new ArrayMap<>();
- @GuardedBy("sCacheLock")
- private static final ArrayMap<File, String> sCachedVolumePathToId = new ArrayMap<>();
-
private static final int sUserId = UserHandle.myUserId();
- // WARNING/TODO (b/173505864): This will be replaced by signature APIs in S
+ /**
+ * Please use {@link getDownloadsProviderAuthority()} instead of using this directly.
+ */
private static final String DOWNLOADS_PROVIDER_AUTHORITY = "downloads";
- @GuardedBy("mShouldRedactThreadIds")
- private final LongArray mShouldRedactThreadIds = new LongArray();
+ @GuardedBy("mPendingOpenInfo")
+ private final Map<Integer, PendingOpenInfo> mPendingOpenInfo = new ArrayMap<>();
@GuardedBy("mNonHiddenPaths")
private final LRUCache<String, Integer> mNonHiddenPaths = new LRUCache<>(NON_HIDDEN_CACHE_SIZE);
public void updateVolumes() {
- synchronized (sCacheLock) {
- sCachedExternalVolumeNames.clear();
- sCachedExternalVolumeNames.addAll(MediaStore.getExternalVolumeNames(getContext()));
- Log.v(TAG, "Updated external volumes to: " + sCachedExternalVolumeNames.toString());
-
- sCachedVolumePaths.clear();
- sCachedVolumeScanPaths.clear();
- sCachedVolumePathToId.clear();
- try {
- sCachedVolumeScanPaths.put(MediaStore.VOLUME_INTERNAL,
- FileUtils.getVolumeScanPaths(getContext(), MediaStore.VOLUME_INTERNAL));
- } catch (FileNotFoundException e) {
- Log.wtf(TAG, "Failed to update volume " + MediaStore.VOLUME_INTERNAL, e);
- }
-
- for (String volumeName : sCachedExternalVolumeNames) {
- try {
- final Uri uri = MediaStore.Files.getContentUri(volumeName);
- final StorageVolume volume = mStorageManager.getStorageVolume(uri);
- sCachedVolumePaths.put(volumeName, volume.getDirectory());
- sCachedVolumeScanPaths.put(volumeName,
- FileUtils.getVolumeScanPaths(getContext(), volumeName));
- sCachedVolumePathToId.put(volume.getDirectory(), volume.getId());
- } catch (IllegalStateException | FileNotFoundException e) {
- Log.wtf(TAG, "Failed to update volume " + volumeName, e);
- }
- }
- }
-
+ mVolumeCache.update();
// Update filters to reflect mounted volumes so users don't get
// confused by metadata from ejected volumes
ForegroundThread.getExecutor().execute(() -> {
- mExternalDatabase.setFilterVolumeNames(getExternalVolumeNames());
+ mExternalDatabase.setFilterVolumeNames(mVolumeCache.getExternalVolumeNames());
});
}
+ public @NonNull MediaVolume getVolume(@NonNull String volumeName) throws FileNotFoundException {
+ return mVolumeCache.findVolume(volumeName, mCallingIdentity.get().getUser());
+ }
+
public @NonNull File getVolumePath(@NonNull String volumeName) throws FileNotFoundException {
// Ugly hack to keep unit tests passing, where we don't always have a
// Context to discover volumes with
@@ -391,64 +411,56 @@
return Environment.getExternalStorageDirectory();
}
- synchronized (sCacheLock) {
- if (sCachedVolumePaths.containsKey(volumeName)) {
- return sCachedVolumePaths.get(volumeName);
- }
-
- // Nothing found above; let's ask directly and cache the answer
- final File res = FileUtils.getVolumePath(getContext(), volumeName);
- sCachedVolumePaths.put(volumeName, res);
- return res;
- }
+ return mVolumeCache.getVolumePath(volumeName, mCallingIdentity.get().getUser());
}
public @NonNull String getVolumeId(@NonNull File file) throws FileNotFoundException {
- synchronized (sCacheLock) {
- for (int i = 0; i < sCachedVolumePathToId.size(); i++) {
- if (FileUtils.contains(sCachedVolumePathToId.keyAt(i), file)) {
- return sCachedVolumePathToId.valueAt(i);
- }
- }
-
- // Nothing found above; let's ask directly and cache the answer
- final StorageVolume volume = mStorageManager.getStorageVolume(file);
- if (volume == null) {
- throw new FileNotFoundException("Missing volume for " + file);
- }
- sCachedVolumePathToId.put(volume.getDirectory(), volume.getId());
- return volume.getId();
- }
+ return mVolumeCache.getVolumeId(file);
}
- public @NonNull Set<String> getExternalVolumeNames() {
- synchronized (sCacheLock) {
- return new ArraySet<>(sCachedExternalVolumeNames);
- }
- }
-
- public @NonNull Collection<File> getVolumeScanPaths(String volumeName)
+ private @NonNull Collection<File> getAllowedVolumePaths(String volumeName)
throws FileNotFoundException {
- synchronized (sCacheLock) {
- if (sCachedVolumeScanPaths.containsKey(volumeName)) {
- return new ArrayList<>(sCachedVolumeScanPaths.get(volumeName));
- }
-
- // Nothing found above; let's ask directly and cache the answer
- final Collection<File> res = FileUtils.getVolumeScanPaths(getContext(), volumeName);
- sCachedVolumeScanPaths.put(volumeName, res);
- return res;
+ // This method is used to verify whether a path belongs to a certain volume name;
+ // we can't always use the calling user's identity here to determine exactly which
+ // volume is meant, because the MediaScanner may scan paths belonging to another user,
+ // eg a clone user.
+ // So, for volumes like external_primary, just return allowed paths for all users.
+ List<UserHandle> users = mUserCache.getUsersCached();
+ ArrayList<File> allowedPaths = new ArrayList<>();
+ for (UserHandle user : users) {
+ Collection<File> volumeScanPaths = mVolumeCache.getVolumeScanPaths(volumeName, user);
+ allowedPaths.addAll(volumeScanPaths);
}
+
+ return allowedPaths;
}
+ /**
+ * Frees any cache held by MediaProvider.
+ *
+ * @param bytes number of bytes which need to be freed
+ */
+ public void freeCache(long bytes) {
+ mTranscodeHelper.freeCache(bytes);
+ }
+
+ public void onAnrDelayStarted(@NonNull String packageName, int uid, int tid, int reason) {
+ mTranscodeHelper.onAnrDelayStarted(packageName, uid, tid, reason);
+ }
+
+ private volatile Locale mLastLocale = Locale.getDefault();
+
private StorageManager mStorageManager;
private AppOpsManager mAppOpsManager;
private PackageManager mPackageManager;
private DevicePolicyManager mDevicePolicyManager;
+ private UserManager mUserManager;
+
+ private UserCache mUserCache;
+ private VolumeCache mVolumeCache;
private int mExternalStorageAuthorityAppId;
private int mDownloadsAuthorityAppId;
-
private Size mThumbSize;
/**
@@ -494,11 +506,11 @@
private LocalCallingIdentity getCachedCallingIdentityForFuse(int uid) {
synchronized (mCachedCallingIdentityForFuse) {
PermissionUtils.setOpDescription("via FUSE");
- LocalCallingIdentity ident = mCachedCallingIdentityForFuse.get(uid);
- if (ident == null) {
- ident = LocalCallingIdentity.fromExternal(getContext(), uid);
+ LocalCallingIdentity identity = mCachedCallingIdentityForFuse.get(uid);
+ if (identity == null) {
+ identity = LocalCallingIdentity.fromExternal(getContext(), uid);
if (uid / PER_USER_RANGE == sUserId) {
- mCachedCallingIdentityForFuse.put(uid, ident);
+ mCachedCallingIdentityForFuse.put(uid, identity);
} else {
// In some app cloning designs, MediaProvider user 0 may
// serve requests for apps running as a "clone" user; in
@@ -506,7 +518,7 @@
// we don't get any invalidation events for these users.
}
}
- return ident;
+ return identity;
}
}
@@ -522,7 +534,7 @@
final LocalCallingIdentity cached = mCachedCallingIdentity
.get(Binder.getCallingUid());
return (cached != null) ? cached
- : LocalCallingIdentity.fromBinder(getContext(), this);
+ : LocalCallingIdentity.fromBinder(getContext(), this, mUserCache);
}
});
@@ -702,6 +714,9 @@
int mediaType, boolean isDownload, String ownerPackageName, String path) {
handleDeletedRowForFuse(path, ownerPackageName, id);
acceptWithExpansion(helper::notifyDelete, volumeName, id, mediaType, isDownload);
+ // Remove cached transcoded file if any
+ mTranscodeHelper.deleteCachedTranscodeFile(id);
+
helper.postBackground(() -> {
// Item no longer exists, so revoke all access to it
@@ -814,7 +829,8 @@
}
private static boolean isCrossUserEnabled() {
- return PROP_CROSS_USER_ALLOWED && Build.VERSION.SDK_INT <= Build.VERSION_CODES.R;
+ return ((PROP_CROSS_USER_ALLOWED && Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) ||
+ SdkLevel.isAtLeastS());
}
/**
@@ -822,39 +838,22 @@
* devices. We only do this once per volume so we don't annoy the user if
* deleted manually.
*/
- private void ensureDefaultFolders(@NonNull String volumeName, @NonNull SQLiteDatabase db) {
- try {
- final File path = getVolumePath(volumeName);
- final StorageVolume vol = mStorageManager.getStorageVolume(path);
- final String key;
- if (vol == null) {
- Log.w(TAG, "Failed to ensure default folders for " + volumeName);
- return;
- }
+ private void ensureDefaultFolders(@NonNull MediaVolume volume, @NonNull SQLiteDatabase db) {
+ final String key = "created_default_folders_" + volume.getId();
- if (vol.isPrimary()) {
- key = "created_default_folders";
- } else {
- key = "created_default_folders_" + vol.getMediaStoreVolumeName();
- }
-
- final SharedPreferences prefs = PreferenceManager
- .getDefaultSharedPreferences(getContext());
- if (prefs.getInt(key, 0) == 0) {
- for (String folderName : DEFAULT_FOLDER_NAMES) {
- final File folder = new File(vol.getDirectory(), folderName);
- if (!folder.exists()) {
- folder.mkdirs();
- insertDirectory(db, folder.getAbsolutePath());
- }
+ final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
+ if (prefs.getInt(key, 0) == 0) {
+ for (String folderName : DEFAULT_FOLDER_NAMES) {
+ final File folder = new File(volume.getPath(), folderName);
+ if (!folder.exists()) {
+ folder.mkdirs();
+ insertDirectory(db, folder.getAbsolutePath());
}
-
- SharedPreferences.Editor editor = prefs.edit();
- editor.putInt(key, 1);
- editor.commit();
}
- } catch (IOException e) {
- Log.w(TAG, "Failed to ensure default folders for " + volumeName, e);
+
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putInt(key, 1);
+ editor.commit();
}
}
@@ -864,10 +863,10 @@
* {@link DatabaseHelper#getOrCreateUuid} doesn't match the UUID found on
* disk, then all thumbnails will be considered stable and will be deleted.
*/
- private void ensureThumbnailsValid(@NonNull String volumeName, @NonNull SQLiteDatabase db) {
+ private void ensureThumbnailsValid(@NonNull MediaVolume volume, @NonNull SQLiteDatabase db) {
final String uuidFromDatabase = DatabaseHelper.getOrCreateUuid(db);
try {
- for (File dir : getThumbnailDirectories(volumeName)) {
+ for (File dir : getThumbnailDirectories(volume)) {
if (!dir.exists()) {
dir.mkdirs();
}
@@ -895,7 +894,7 @@
}
}
} catch (IOException e) {
- Log.w(TAG, "Failed to ensure thumbnails valid for " + volumeName, e);
+ Log.w(TAG, "Failed to ensure thumbnails valid for " + volume.getName(), e);
}
}
@@ -912,6 +911,8 @@
public boolean onCreate() {
final Context context = getContext();
+ mUserCache = new UserCache(context);
+
// Shift call statistics back to the original caller
Binder.setProxyTransactListener(mTransactListener);
@@ -919,6 +920,8 @@
mAppOpsManager = context.getSystemService(AppOpsManager.class);
mPackageManager = context.getPackageManager();
mDevicePolicyManager = context.getSystemService(DevicePolicyManager.class);
+ mUserManager = context.getSystemService(UserManager.class);
+ mVolumeCache = new VolumeCache(context, mUserCache);
// Reasonable thumbnail size is half of the smallest screen edge width
final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
@@ -934,6 +937,11 @@
false, false, false, Column.class,
Metrics::logSchemaChange, mFilesListener, MIGRATION_LISTENER, mIdGenerator);
+ mTranscodeHelper = new TranscodeHelper(context, this);
+
+ // Create dir for redacted URI's path.
+ new File("/storage/emulated/" + UserHandle.myUserId(), REDACTED_URI_DIR).mkdirs();
+
final IntentFilter packageFilter = new IntentFilter();
packageFilter.setPriority(10);
packageFilter.addDataScheme("package");
@@ -951,9 +959,9 @@
});
updateVolumes();
- attachVolume(MediaStore.VOLUME_INTERNAL, /* validate */ false);
- for (String volumeName : getExternalVolumeNames()) {
- attachVolume(volumeName, /* validate */ false);
+ attachVolume(MediaVolume.fromInternal(), /* validate */ false);
+ for (MediaVolume volume : mVolumeCache.getExternalVolumes()) {
+ attachVolume(volume, /* validate */ false);
}
// Watch for performance-sensitive activity
@@ -984,27 +992,26 @@
// throw an IllegalArgumentException during MediaProvider startup. In combination with
// MediaProvider's CTS tests it should give us guarantees that OPSTR_NO_ISOLATED_STORAGE
// is defined.
- mAppOpsManager.startWatchingMode(PermissionUtils.OPSTR_NO_ISOLATED_STORAGE,
+ mAppOpsManager.startWatchingMode(AppOpsManager.OPSTR_NO_ISOLATED_STORAGE,
null /* all packages */, mModeListener);
} catch (IllegalArgumentException e) {
- Log.w(TAG, "Failed to start watching " + PermissionUtils.OPSTR_NO_ISOLATED_STORAGE, e);
+ Log.w(TAG, "Failed to start watching " + AppOpsManager.OPSTR_NO_ISOLATED_STORAGE, e);
}
ProviderInfo provider = mPackageManager.resolveContentProvider(
- DOWNLOADS_PROVIDER_AUTHORITY, PackageManager.MATCH_DIRECT_BOOT_AWARE
+ getDownloadsProviderAuthority(), PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
if (provider != null) {
mDownloadsAuthorityAppId = UserHandle.getAppId(provider.applicationInfo.uid);
}
- provider = mPackageManager.resolveContentProvider(
- MediaStore.EXTERNAL_STORAGE_PROVIDER_AUTHORITY, PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
+ provider = mPackageManager.resolveContentProvider(getExternalStorageProviderAuthority(),
+ PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
if (provider != null) {
mExternalStorageAuthorityAppId = UserHandle.getAppId(provider.applicationInfo.uid);
}
- StatsdPuller.initialize(context);
+ PulledMetrics.initialize(context);
return true;
}
@@ -1015,7 +1022,11 @@
}
public LocalCallingIdentity clearLocalCallingIdentity() {
- return clearLocalCallingIdentity(LocalCallingIdentity.fromSelf(getContext()));
+ // We retain the user part of the calling identity, since we are executing
+ // the call on behalf of that user, and we need to maintain the user context
+ // to correctly resolve things like volumes
+ UserHandle user = mCallingIdentity.get().getUser();
+ return clearLocalCallingIdentity(LocalCallingIdentity.fromSelfAsUser(getContext(), user));
}
public LocalCallingIdentity clearLocalCallingIdentity(LocalCallingIdentity replacement) {
@@ -1056,19 +1067,19 @@
Logging.trimPersistent();
// Scan all volumes to resolve any staleness
- for (String volumeName : getExternalVolumeNames()) {
+ for (MediaVolume volume : mVolumeCache.getExternalVolumes()) {
// Possibly bail before digging into each volume
signal.throwIfCanceled();
try {
- MediaService.onScanVolume(getContext(), volumeName, REASON_IDLE);
+ MediaService.onScanVolume(getContext(), volume, REASON_IDLE);
} catch (IOException e) {
Log.w(TAG, e);
}
// Ensure that our thumbnails are valid
mExternalDatabase.runWithTransaction((db) -> {
- ensureThumbnailsValid(volumeName, db);
+ ensureThumbnailsValid(volume, db);
return null;
});
}
@@ -1264,7 +1275,7 @@
}
public Uri scanFile(File file, int reason) {
- return mMediaScanner.scanFile(file, reason);
+ return scanFile(file, reason, null);
}
public Uri scanFile(File file, int reason, String ownerPackage) {
@@ -1299,9 +1310,20 @@
private boolean isAppCloneUserPair(int userId1, int userId2) {
try {
- Method isAppCloneUserPair = StorageManager.class.getMethod("isAppCloneUserPair",
+ UserHandle user1 = UserHandle.of(userId1);
+ UserHandle user2 = UserHandle.of(userId2);
+ if (Build.VERSION.DEVICE_INITIAL_SDK_INT < Build.VERSION_CODES.S) {
+ if (SdkLevel.isAtLeastS() && (mUserCache.userSharesMediaWithParent(user1)
+ || mUserCache.userSharesMediaWithParent(user2))) {
+ return true;
+ }
+ Method isAppCloneUserPair = StorageManager.class.getMethod("isAppCloneUserPair",
int.class, int.class);
- return (Boolean) isAppCloneUserPair.invoke(mStorageManager, userId1, userId2);
+ return (Boolean) isAppCloneUserPair.invoke(mStorageManager, userId1, userId2);
+ } else {
+ return (mUserCache.userSharesMediaWithParent(user1)
+ || mUserCache.userSharesMediaWithParent(user2));
+ }
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
Log.w(TAG, "isAppCloneUserPair failed. Users: " + userId1 + " and " + userId2);
return false;
@@ -1322,6 +1344,7 @@
return false;
}
boolean result = isAppCloneUserPair(0, userId);
+
Log.w(TAG, "isAppCloneUserPair for user " + userId + ": " + result);
return result;
@@ -1343,7 +1366,7 @@
return false;
}
- if (callingUserId != 0 && pathUserId != 0) {
+ if (callingUserId != pathUserId && callingUserId != 0 && pathUserId != 0) {
Log.w(TAG, "CrossUser at least one user is 0 check failed. Users: " + callingUserId
+ " and " + pathUserId);
return false;
@@ -1395,6 +1418,170 @@
}
/**
+ * Called from FUSE to transform a file
+ *
+ * A transform can change the file contents for {@code uid} from {@code src} to {@code dst}
+ * depending on {@code flags}. This allows the FUSE daemon serve different file contents for
+ * the same file to different apps.
+ *
+ * The only supported transform for now is transcoding which re-encodes a file taken in a modern
+ * format like HEVC to a legacy format like AVC.
+ *
+ * @param src file path to transform
+ * @param dst file path to save transformed file
+ * @param flags determines the kind of transform
+ * @param readUid app that called us requesting transform
+ * @param openUid app that originally made the open call
+ * @param mediaCapabilitiesUid app for which the transform decision was made,
+ * 0 if decision was made with openUid
+ *
+ * Called from JNI in jni/MediaProviderWrapper.cpp
+ */
+ @Keep
+ public boolean transformForFuse(String src, String dst, int transforms, int transformsReason,
+ int readUid, int openUid, int mediaCapabilitiesUid) {
+ if ((transforms & FLAG_TRANSFORM_TRANSCODING) != 0) {
+ if (mTranscodeHelper.isTranscodeFileCached(src, dst)) {
+ Log.d(TAG, "Using transcode cache for " + src);
+ return true;
+ }
+
+ // In general we always mark the opener as causing transcoding.
+ // However, if the mediaCapabilitiesUid is available then we mark the reader as causing
+ // transcoding. This handles the case where a malicious app might want to take
+ // advantage of mediaCapabilitiesUid by setting it to another app's uid and reading the
+ // media contents itself; in such cases we'd mark the reader (malicious app) for the
+ // cost of transcoding.
+ //
+ // openUid readUid mediaCapabilitiesUid
+ // -------------------------------------------------------------------------------------
+ // using picker SAF app app
+ // abusive case bad app bad app victim
+ // modern to lega-
+ // -cy sharing modern legacy legacy
+ //
+ // we'd not be here in the below case.
+ // legacy to mode-
+ // -rn sharing legacy modern modern
+
+ int transcodeUid = openUid;
+ if (mediaCapabilitiesUid > 0) {
+ Log.d(TAG, "Fix up transcodeUid to " + readUid + ". openUid " + openUid
+ + ", mediaCapabilitiesUid " + mediaCapabilitiesUid);
+ transcodeUid = readUid;
+ }
+ return mTranscodeHelper.transcode(src, dst, transcodeUid, transformsReason);
+ }
+ return true;
+ }
+
+ /**
+ * Called from FUSE to get {@link FileLookupResult} for a {@code path} and {@code uid}
+ *
+ * {@link FileLookupResult} contains transforms, transforms completion status and ioPath
+ * for transform lookup query for a file and uid.
+ *
+ * @param path file path to get transforms for
+ * @param uid app requesting IO form kernel
+ * @param tid FUSE thread id handling IO request from kernel
+ *
+ * Called from JNI in jni/MediaProviderWrapper.cpp
+ */
+ @Keep
+ public FileLookupResult onFileLookupForFuse(String path, int uid, int tid) {
+ uid = getBinderUidForFuse(uid, tid);
+ if (isSyntheticFilePathForRedactedUri(path, uid)) {
+ return getFileLookupResultsForRedactedUriPath(uid, path);
+ }
+
+ String ioPath = "";
+ boolean transformsComplete = true;
+ boolean transformsSupported = mTranscodeHelper.supportsTranscode(path);
+ int transforms = 0;
+ int transformsReason = 0;
+
+ if (transformsSupported) {
+ PendingOpenInfo info = null;
+ synchronized (mPendingOpenInfo) {
+ info = mPendingOpenInfo.get(tid);
+ }
+
+ if (info != null && info.uid == uid) {
+ transformsReason = info.transcodeReason;
+ } else {
+ transformsReason = mTranscodeHelper.shouldTranscode(path, uid, null /* bundle */);
+ }
+
+ if (transformsReason > 0) {
+ ioPath = mTranscodeHelper.getIoPath(path, uid);
+ transformsComplete = mTranscodeHelper.isTranscodeFileCached(path, ioPath);
+ transforms = FLAG_TRANSFORM_TRANSCODING;
+ }
+ }
+
+ return new FileLookupResult(transforms, transformsReason, uid, transformsComplete,
+ transformsSupported, ioPath);
+ }
+
+ private boolean isSyntheticFilePathForRedactedUri(String path, int uid) {
+ if (path == null) return false;
+
+ final String transformsSyntheticDir = getStorageRootPathForUid(uid) + "/"
+ + REDACTED_URI_DIR;
+ final String fileName = extractFileName(path);
+ return fileName != null && path.toLowerCase(Locale.ROOT).startsWith(
+ transformsSyntheticDir.toLowerCase(Locale.ROOT)) && fileName.startsWith(
+ REDACTED_URI_ID_PREFIX) && fileName.length() == REDACTED_URI_ID_SIZE;
+ }
+
+ private boolean isSyntheticDirPath(String path, int uid) {
+ final String transformsSyntheticDir = getStorageRootPathForUid(uid) + "/"
+ + TRANSFORMS_SYNTHETIC_DIR;
+ return path != null && path.toLowerCase(Locale.ROOT).startsWith(
+ transformsSyntheticDir.toLowerCase(Locale.ROOT));
+ }
+
+ private FileLookupResult getFileLookupResultsForRedactedUriPath(int uid, @NonNull String path) {
+ final LocalCallingIdentity token = clearLocalCallingIdentity();
+ final String fileName = extractFileName(path);
+
+ final DatabaseHelper helper;
+ try {
+ helper = getDatabaseForUri(FileUtils.getContentUriForPath(path));
+ } catch (VolumeNotFoundException e) {
+ throw new IllegalStateException("Volume not found for file: " + path);
+ }
+
+ try (final Cursor c = helper.runWithoutTransaction(
+ (db) -> db.query("files", new String[]{MediaColumns.DATA},
+ FileColumns.REDACTED_URI_ID + "=?", new String[]{fileName}, null, null,
+ null))) {
+ if (!c.moveToFirst()) {
+ return new FileLookupResult(FLAG_TRANSFORM_REDACTION, 0, uid, false, true, null);
+ }
+
+ return new FileLookupResult(FLAG_TRANSFORM_REDACTION, 0, uid, true, true,
+ c.getString(0));
+ } finally {
+ restoreLocalCallingIdentity(token);
+ }
+ }
+
+ public int getBinderUidForFuse(int uid, int tid) {
+ if (uid != MY_UID) {
+ return uid;
+ }
+
+ synchronized (mPendingOpenInfo) {
+ PendingOpenInfo info = mPendingOpenInfo.get(tid);
+ if (info == null) {
+ return uid;
+ }
+ return info.uid;
+ }
+ }
+
+ /**
* Returns true if the app denoted by the given {@code uid} and {@code packageName} is allowed
* to clear other apps' cache directories.
*/
@@ -1606,16 +1793,23 @@
* <li> {@code column} is set or
* <li> {@code column} is {@link MediaColumns#IS_PENDING} and is set by FUSE and not owned by
* calling package.
+ * <li> {@code column} is {@link MediaColumns#IS_PENDING}, is unset and is waiting for
+ * metadata update from a deferred scan.
* </ul>
*/
private String getWhereClauseForMatchExclude(@NonNull String column) {
if (column.equalsIgnoreCase(MediaColumns.IS_PENDING)) {
- final String callingPackage = getCallingPackageOrSelf();
+ // Don't include rows that are pending for metadata
+ final String pendingForMetadata = FileColumns._MODIFIER + "="
+ + FileColumns._MODIFIER_CR_PENDING_METADATA;
+ final String notPending = String.format("(%s=0 AND NOT %s)", column,
+ pendingForMetadata);
final String matchSharedPackagesClause = FileColumns.OWNER_PACKAGE_NAME + " IN "
+ getSharedPackages();
// Include owned pending files from Fuse
- return String.format("%s=0 OR (%s=1 AND %s AND %s)", column, column,
+ final String pendingFromFuse = String.format("(%s=1 AND %s AND %s)", column,
MATCH_PENDING_FROM_FUSE, matchSharedPackagesClause);
+ return "(" + notPending + " OR " + pendingFromFuse + ")";
}
return column + "=0";
}
@@ -1737,6 +1931,7 @@
public String[] getFilesInDirectoryForFuse(String path, int uid) {
final LocalCallingIdentity token =
clearLocalCallingIdentity(getCachedCallingIdentityForFuse(uid));
+ PulledMetrics.logFileAccessViaFuse(getCallingUidOrSelf(), path);
try {
if (isPrivatePackagePathNotAccessibleByCaller(path)) {
@@ -1887,13 +2082,19 @@
return updateDatabaseForFuseRename(helper, oldPath, newPath, values, Bundle.EMPTY);
}
+ private boolean updateDatabaseForFuseRename(@NonNull DatabaseHelper helper,
+ @NonNull String oldPath, @NonNull String newPath, @NonNull ContentValues values,
+ @NonNull Bundle qbExtras) {
+ return updateDatabaseForFuseRename(helper, oldPath, newPath, values, qbExtras,
+ FileUtils.getContentUriForPath(oldPath));
+ }
+
/**
* Updates database entry for given {@code path} with {@code values}
*/
private boolean updateDatabaseForFuseRename(@NonNull DatabaseHelper helper,
@NonNull String oldPath, @NonNull String newPath, @NonNull ContentValues values,
- @NonNull Bundle qbExtras) {
- final Uri uriOldPath = FileUtils.getContentUriForPath(oldPath);
+ @NonNull Bundle qbExtras, Uri uriOldPath) {
boolean allowHidden = isCallingPackageAllowedHidden();
final SQLiteQueryBuilder qbForUpdate = getQueryBuilder(TYPE_UPDATE,
matchUri(uriOldPath, allowHidden), uriOldPath, qbExtras, null);
@@ -2225,12 +2426,17 @@
final String newMimeType = MimeUtils.resolveMimeType(new File(newPath));
final String oldMimeType = MimeUtils.resolveMimeType(new File(oldPath));
final boolean isSameMimeType = newMimeType.equalsIgnoreCase(oldMimeType);
- if (!updateDatabaseForFuseRename(helper, oldPath, newPath,
- getContentValuesForFuseRename(newPath, newMimeType, wasHidden, isHidden,
- isSameMimeType))) {
+ final ContentValues contentValues = getContentValuesForFuseRename(newPath, newMimeType,
+ wasHidden, isHidden, isSameMimeType);
+
+ if (!updateDatabaseForFuseRename(helper, oldPath, newPath, contentValues)) {
if (!bypassRestrictions) {
- Log.e(TAG, "Calling package doesn't have write permission to rename file.");
- return OsConstants.EPERM;
+ // Check for other URI format grants for oldPath only. Check right before
+ // returning EPERM, to leave positive case performance unaffected.
+ if (!renameWithOtherUriGrants(helper, oldPath, newPath, contentValues)) {
+ Log.e(TAG, "Calling package doesn't have write permission to rename file.");
+ return OsConstants.EPERM;
+ }
} else if (!maybeRemoveOwnerPackageForFuseRename(helper, newPath)) {
Log.wtf(TAG, "Couldn't clear owner package name for " + newPath);
return OsConstants.EPERM;
@@ -2268,6 +2474,21 @@
}
/**
+ * Rename file by checking for other URI grants on oldPath
+ *
+ * We don't support replace scenario by checking for other URI grants on newPath (if it exists).
+ */
+ private boolean renameWithOtherUriGrants(DatabaseHelper helper, String oldPath, String newPath,
+ ContentValues contentValues) {
+ final Uri oldPathGrantedUri = getOtherUriGrantsForPath(oldPath, /* forWrite */ true);
+ if (oldPathGrantedUri == null) {
+ return false;
+ }
+ return updateDatabaseForFuseRename(helper, oldPath, newPath, contentValues, Bundle.EMPTY,
+ oldPathGrantedUri);
+ }
+
+ /**
* Rename file/directory without imposing any restrictions.
*
* We don't impose any rename restrictions for apps that bypass scoped storage restrictions.
@@ -2303,6 +2524,7 @@
final String errorMessage = "Rename " + oldPath + " to " + newPath + " failed. ";
final LocalCallingIdentity token =
clearLocalCallingIdentity(getCachedCallingIdentityForFuse(uid));
+ PulledMetrics.logFileAccessViaFuse(getCallingUidOrSelf(), oldPath);
try {
if (isPrivatePackagePathNotAccessibleByCaller(oldPath)
@@ -2399,6 +2621,15 @@
final LocalCallingIdentity token = clearLocalCallingIdentity(
LocalCallingIdentity.fromExternal(getContext(), uid));
+ if(isRedactedUri(uri)) {
+ if((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
+ // we don't allow write grants on redacted uris.
+ return PackageManager.PERMISSION_DENIED;
+ }
+
+ uri = getUriForRedactedUri(uri);
+ }
+
try {
final boolean allowHidden = isCallingPackageAllowedHidden();
final int table = matchUri(uri, allowHidden);
@@ -2477,6 +2708,8 @@
private Cursor queryInternal(Uri uri, String[] projection, Bundle queryArgs,
CancellationSignal signal, boolean forSelf) throws FallbackException {
+ final String volumeName = getVolumeName(uri);
+ PulledMetrics.logVolumeAccessViaMediaProvider(getCallingUidOrSelf(), volumeName);
queryArgs = (queryArgs != null) ? queryArgs : new Bundle();
// INCLUDED_DEFAULT_DIRECTORIES extra should only be set inside MediaProvider.
@@ -2485,9 +2718,17 @@
final ArraySet<String> honoredArgs = new ArraySet<>();
DatabaseUtils.resolveQueryArgs(queryArgs, honoredArgs::add, this::ensureCustomCollator);
+ Uri redactedUri = null;
+ // REDACTED_URI_BUNDLE_KEY extra should only be set inside MediaProvider.
+ queryArgs.remove(QUERY_ARG_REDACTED_URI);
+ if (isRedactedUri(uri)) {
+ redactedUri = uri;
+ uri = getUriForRedactedUri(uri);
+ queryArgs.putParcelable(QUERY_ARG_REDACTED_URI, redactedUri);
+ }
+
uri = safeUncanonicalize(uri);
- final String volumeName = getVolumeName(uri);
final int targetSdkVersion = getCallingPackageTargetSdkVersion();
final boolean allowHidden = isCallingPackageAllowedHidden();
final int table = matchUri(uri, allowHidden);
@@ -2577,6 +2818,12 @@
}
}
+ // Update locale if necessary.
+ if (helper == mInternalDatabase && !Locale.getDefault().equals(mLastLocale)) {
+ Log.i(TAG, "Updating locale within queryInternal");
+ onLocaleChanged(false);
+ }
+
final Cursor c = qb.query(helper, projection, queryArgs, signal);
if (c != null && !forSelf) {
// As a performance optimization, only configure notifications when
@@ -2591,9 +2838,131 @@
honoredArgs.toArray(new String[honoredArgs.size()]));
c.setExtras(extras);
}
+
+ // Query was on a redacted URI, update the sensitive information such as the _ID, DATA etc.
+ if (redactedUri != null && c != null) {
+ try {
+ return getRedactedUriCursor(redactedUri, c);
+ } finally {
+ c.close();
+ }
+ }
+
return c;
}
+ private boolean isUriSupportedForRedaction(Uri uri) {
+ final int match = matchUri(uri, true);
+ return REDACTED_URI_SUPPORTED_TYPES.contains(match);
+ }
+
+ private Cursor getRedactedUriCursor(Uri redactedUri, @NonNull Cursor c) {
+ final HashSet<String> columnNames = new HashSet<>(Arrays.asList(c.getColumnNames()));
+ final MatrixCursor redactedUriCursor = new MatrixCursor(c.getColumnNames());
+ final String redactedUriId = redactedUri.getLastPathSegment();
+
+ if (!c.moveToFirst()) {
+ return redactedUriCursor;
+ }
+
+ // NOTE: It is safe to assume that there will only be one entry corresponding to a
+ // redacted URI as it corresponds to a unique DB entry.
+ if (c.getCount() != 1) {
+ throw new AssertionError("Two rows corresponding to " + redactedUri.toString()
+ + " found, when only one expected");
+ }
+
+ final MatrixCursor.RowBuilder row = redactedUriCursor.newRow();
+ for (String columnName : c.getColumnNames()) {
+ final int colIndex = c.getColumnIndex(columnName);
+ if (c.getType(colIndex) == FIELD_TYPE_BLOB) {
+ row.add(c.getBlob(colIndex));
+ } else {
+ row.add(c.getString(colIndex));
+ }
+ }
+
+ String ext = getFileExtensionFromCursor(c, columnNames);
+ ext = ext == null ? "" : "." + ext;
+ final String displayName = redactedUriId + ext;
+ final String data = getPathForRedactedUriId(displayName);
+
+
+ updateRow(columnNames, MediaColumns._ID, row, redactedUriId);
+ updateRow(columnNames, MediaColumns.DISPLAY_NAME, row, displayName);
+ updateRow(columnNames, MediaColumns.RELATIVE_PATH, row, REDACTED_URI_DIR);
+ updateRow(columnNames, MediaColumns.BUCKET_DISPLAY_NAME, row, REDACTED_URI_DIR);
+ updateRow(columnNames, MediaColumns.DATA, row, data);
+ updateRow(columnNames, MediaColumns.DOCUMENT_ID, row, null);
+ updateRow(columnNames, MediaColumns.INSTANCE_ID, row, null);
+ updateRow(columnNames, MediaColumns.BUCKET_ID, row, null);
+
+ return redactedUriCursor;
+ }
+
+ @Nullable
+ private static String getFileExtensionFromCursor(@NonNull Cursor c,
+ @NonNull HashSet<String> columnNames) {
+ if (columnNames.contains(MediaColumns.DATA)) {
+ return extractFileExtension(c.getString(c.getColumnIndex(MediaColumns.DATA)));
+ }
+ if (columnNames.contains(MediaColumns.DISPLAY_NAME)) {
+ return extractFileExtension(c.getString(c.getColumnIndex(MediaColumns.DISPLAY_NAME)));
+ }
+ return null;
+ }
+
+ static private String getPathForRedactedUriId(@NonNull String displayName) {
+ return getStorageRootPathForUid(Binder.getCallingUid()) + "/" + REDACTED_URI_DIR + "/"
+ + displayName;
+ }
+
+ static private String getStorageRootPathForUid(int uid) {
+ return "/storage/emulated/" + (uid / PER_USER_RANGE);
+ }
+
+ private void updateRow(HashSet<String> columnNames, String columnName,
+ MatrixCursor.RowBuilder row, Object val) {
+ if (columnNames.contains(columnName)) {
+ row.add(columnName, val);
+ }
+ }
+
+ private Uri getUriForRedactedUri(Uri redactedUri) {
+ final Uri.Builder builder = redactedUri.buildUpon();
+ builder.path(null);
+ final List<String> segments = redactedUri.getPathSegments();
+ for (int i = 0; i < segments.size() - 1; i++) {
+ builder.appendPath(segments.get(i));
+ }
+
+ DatabaseHelper helper;
+ try {
+ helper = getDatabaseForUri(redactedUri);
+ } catch (VolumeNotFoundException e) {
+ throw e.rethrowAsIllegalArgumentException();
+ }
+
+ try (final Cursor c = helper.runWithoutTransaction(
+ (db) -> db.query("files", new String[]{MediaColumns._ID},
+ FileColumns.REDACTED_URI_ID + "=?",
+ new String[]{redactedUri.getLastPathSegment()}, null, null, null))) {
+ if (!c.moveToFirst()) {
+ throw new IllegalArgumentException(
+ "Uri: " + redactedUri.toString() + " not found.");
+ }
+
+ builder.appendPath(c.getString(0));
+ return builder.build();
+ }
+ }
+
+ private boolean isRedactedUri(Uri uri) {
+ String id = uri.getLastPathSegment();
+ return id != null && id.startsWith(REDACTED_URI_ID_PREFIX)
+ && id.length() == REDACTED_URI_ID_SIZE;
+ }
+
@Override
public String getType(Uri url) {
final int match = matchUri(url, true);
@@ -2669,7 +3038,7 @@
/**
* Get the various file-related {@link MediaColumns} in the given
- * {@link ContentValues} into sane condition. Also validates that defined
+ * {@link ContentValues} into a consistent condition. Also validates that defined
* columns are valid for the given {@link Uri}, such as ensuring that only
* {@code image/*} can be inserted into
* {@link android.provider.MediaStore.Images}.
@@ -2697,13 +3066,25 @@
defaultMimeType = "audio/mpeg";
defaultMediaType = FileColumns.MEDIA_TYPE_AUDIO;
defaultPrimary = Environment.DIRECTORY_MUSIC;
- allowedPrimary = Arrays.asList(
- Environment.DIRECTORY_ALARMS,
- Environment.DIRECTORY_AUDIOBOOKS,
- Environment.DIRECTORY_MUSIC,
- Environment.DIRECTORY_NOTIFICATIONS,
- Environment.DIRECTORY_PODCASTS,
- Environment.DIRECTORY_RINGTONES);
+ if (SdkLevel.isAtLeastS()) {
+ allowedPrimary = Arrays.asList(
+ Environment.DIRECTORY_ALARMS,
+ Environment.DIRECTORY_AUDIOBOOKS,
+ Environment.DIRECTORY_MUSIC,
+ Environment.DIRECTORY_NOTIFICATIONS,
+ Environment.DIRECTORY_PODCASTS,
+ Environment.DIRECTORY_RECORDINGS,
+ Environment.DIRECTORY_RINGTONES);
+ } else {
+ allowedPrimary = Arrays.asList(
+ Environment.DIRECTORY_ALARMS,
+ Environment.DIRECTORY_AUDIOBOOKS,
+ Environment.DIRECTORY_MUSIC,
+ Environment.DIRECTORY_NOTIFICATIONS,
+ Environment.DIRECTORY_PODCASTS,
+ FileUtils.DIRECTORY_RECORDINGS,
+ Environment.DIRECTORY_RINGTONES);
+ }
break;
case VIDEO_MEDIA:
case VIDEO_MEDIA_ID:
@@ -2836,7 +3217,7 @@
}
}
- // Give ourselves sane defaults when missing
+ // Give ourselves reasonable defaults when missing
if (TextUtils.isEmpty(values.getAsString(MediaColumns.DISPLAY_NAME))) {
values.put(MediaColumns.DISPLAY_NAME,
String.valueOf(System.currentTimeMillis()));
@@ -2848,8 +3229,9 @@
}
mimeType = values.getAsString(MediaColumns.MIME_TYPE);
- // Sanity check MIME type against table
+ // Quick check MIME type against table
if (mimeType != null) {
+ PulledMetrics.logMimeTypeAccess(getCallingUidOrSelf(), mimeType);
final int actualMediaType = MimeUtils.resolveMediaType(mimeType);
if (defaultMediaType == FileColumns.MEDIA_TYPE_NONE) {
// Give callers an opportunity to work with playlists and
@@ -2934,8 +3316,8 @@
if (!validPath) {
// Some app-clone implementations use a subdirectory of the main user's root
// to store app clone files; allow these as well.
- if (isCrossUserEnabled() && primary.equals(PROP_CROSS_USER_ROOT) &&
- relativePath.length >= 2) {
+ if (isCrossUserEnabled() && primary != null &&
+ primary.equals(PROP_CROSS_USER_ROOT) && relativePath.length >= 2) {
final String crossUserPrimary = relativePath[1];
validPath = containsIgnoreCase(allowedPrimary, crossUserPrimary);
}
@@ -3029,9 +3411,11 @@
// files DISPLAY_NAME will not be same as file name.
FileUtils.computeValuesFromData(values, isFuseThread);
} else {
- assertFileColumnsSane(match, uri, values);
+ assertFileColumnsConsistent(match, uri, values);
}
+ assertPrivatePathNotInValues(values);
+
// Drop columns that aren't relevant for special tables
switch (match) {
case AUDIO_ALBUMART:
@@ -3051,6 +3435,44 @@
}
/**
+ * Check that values don't contain any external private path.
+ * NOTE: The checks are gated on targetSDK S.
+ */
+ private void assertPrivatePathNotInValues(ContentValues values)
+ throws IllegalArgumentException {
+ if (!CompatChanges.isChangeEnabled(ENABLE_CHECKS_FOR_PRIVATE_FILES,
+ Binder.getCallingUid())) {
+ // For legacy apps, let the behaviour be as it is.
+ return;
+ }
+
+ ArrayList<String> relativePaths = new ArrayList<String>();
+ relativePaths.add(extractRelativePath(values.getAsString(MediaColumns.DATA)));
+ relativePaths.add(values.getAsString(MediaColumns.RELATIVE_PATH));
+ /**
+ * Don't allow apps to insert/update database row to files in Android/data or
+ * Android/obb dirs. These are app private directories and files in these private
+ * directories can't be added to public media collection.
+ */
+ for (final String relativePath : relativePaths) {
+ if (relativePath == null) continue;
+
+ final String[] relativePathSegments = relativePath.split("/", 3);
+ final String primary =
+ (relativePathSegments.length > 0) ? relativePathSegments[0] : null;
+ final String secondary =
+ (relativePathSegments.length > 1) ? relativePathSegments[1] : "";
+
+ if (DIRECTORY_ANDROID_LOWER_CASE.equalsIgnoreCase(primary)
+ && PRIVATE_SUBDIRECTORIES_ANDROID.contains(
+ secondary.toLowerCase(Locale.ROOT))) {
+ throw new IllegalArgumentException(
+ "Inserting private file: " + relativePath + " is not allowed.");
+ }
+ }
+ }
+
+ /**
* @return the default dir if {@code file} is a child of default dir and it's missing,
* {@code null} otherwise.
*/
@@ -3086,14 +3508,14 @@
* Check that any requested {@link MediaColumns#DATA} paths actually
* live on the storage volume being targeted.
*/
- private void assertFileColumnsSane(int match, Uri uri, ContentValues values)
+ private void assertFileColumnsConsistent(int match, Uri uri, ContentValues values)
throws VolumeArgumentException, VolumeNotFoundException {
if (!values.containsKey(MediaColumns.DATA)) return;
final String volumeName = resolveVolumeName(uri);
try {
- // Sanity check that the requested path actually lives on volume
- final Collection<File> allowed = getVolumeScanPaths(volumeName);
+ // Quick check that the requested path actually lives on volume
+ final Collection<File> allowed = getAllowedVolumePaths(volumeName);
final File actual = new File(values.getAsString(MediaColumns.DATA))
.getCanonicalFile();
if (!FileUtils.contains(allowed, actual)) {
@@ -3328,8 +3750,15 @@
}
public void onLocaleChanged() {
+ onLocaleChanged(true);
+ }
+
+ private void onLocaleChanged(boolean forceUpdate) {
mInternalDatabase.runWithTransaction((db) -> {
- localizeTitles(db);
+ if (forceUpdate || !mLastLocale.equals(Locale.getDefault())) {
+ localizeTitles(db);
+ mLastLocale = Locale.getDefault();
+ }
return null;
});
}
@@ -3437,7 +3866,20 @@
values.put(FileColumns._MODIFIER, FileColumns._MODIFIER_CR);
}
+ // There is no meaning of an owner in the internal storage. It is shared by all users.
+ // So we only set the user_id field in the database for external storage.
+ qb.allowColumn(FileColumns._USER_ID);
+ int ownerUserId = FileUtils.extractUserId(path);
+ if (!helper.mInternal) {
+ if (isAppCloneUserForFuse(ownerUserId)) {
+ values.put(FileColumns._USER_ID, ownerUserId);
+ } else {
+ values.put(FileColumns._USER_ID, sUserId);
+ }
+ }
+
final long rowId;
+ Uri newUri = uri;
{
if (mediaType == FileColumns.MEDIA_TYPE_PLAYLIST) {
String name = values.getAsString(Audio.Playlists.NAME);
@@ -3464,6 +3906,12 @@
values.put(FileColumns.SIZE, file.length());
}
}
+ // Checking if the file/directory is hidden can be expensive based on the depth of
+ // the directory tree. Call shouldFileBeHidden() only when the caller of insert()
+ // cares about returned uri.
+ if (!isCallingPackageSelf() && !isFuseThread() && shouldFileBeHidden(file)) {
+ newUri = MediaStore.Files.getContentUri(MediaStore.getVolumeName(uri));
+ }
}
rowId = insertAllowingUpsert(qb, helper, values, path);
@@ -3474,7 +3922,7 @@
}
}
- return ContentUris.withAppendedId(uri, rowId);
+ return ContentUris.withAppendedId(newUri, rowId);
}
/**
@@ -3643,7 +4091,12 @@
private @Nullable Uri insertInternal(@NonNull Uri uri, @Nullable ContentValues initialValues,
@Nullable Bundle extras) throws FallbackException {
+ final String originalVolumeName = getVolumeName(uri);
+ PulledMetrics.logVolumeAccessViaMediaProvider(getCallingUidOrSelf(), originalVolumeName);
+
extras = (extras != null) ? extras : new Bundle();
+ // REDACTED_URI_BUNDLE_KEY extra should only be set inside MediaProvider.
+ extras.remove(QUERY_ARG_REDACTED_URI);
// INCLUDED_DEFAULT_DIRECTORIES extra should only be set inside MediaProvider.
extras.remove(INCLUDED_DEFAULT_DIRECTORIES);
@@ -3652,7 +4105,6 @@
final int match = matchUri(uri, allowHidden);
final int targetSdkVersion = getCallingPackageTargetSdkVersion();
- final String originalVolumeName = getVolumeName(uri);
final String resolvedVolumeName = resolveVolumeName(uri);
// handle MEDIA_SCANNER before calling getDatabaseForUri()
@@ -3668,13 +4120,20 @@
if (match == VOLUMES) {
String name = initialValues.getAsString("name");
- Uri attachedVolume = attachVolume(name, /* validate */ true);
- if (mMediaScannerVolume != null && mMediaScannerVolume.equals(name)) {
- final DatabaseHelper helper = getDatabaseForUri(
- MediaStore.Files.getContentUri(mMediaScannerVolume));
- helper.mScanStartTime = SystemClock.elapsedRealtime();
+ MediaVolume volume = null;
+ try {
+ volume = getVolume(name);
+ Uri attachedVolume = attachVolume(volume, /* validate */ true);
+ if (mMediaScannerVolume != null && mMediaScannerVolume.equals(name)) {
+ final DatabaseHelper helper = getDatabaseForUri(
+ MediaStore.Files.getContentUri(mMediaScannerVolume));
+ helper.mScanStartTime = SystemClock.elapsedRealtime();
+ }
+ return attachedVolume;
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "Couldn't find volume with name " + volume.getName());
+ return null;
}
- return attachedVolume;
}
final DatabaseHelper helper = getDatabaseForUri(uri);
@@ -4019,6 +4478,14 @@
}
}
+ /**
+ * Gets {@link LocalCallingIdentity} for the calling package
+ * TODO(b/170465810) Change the method name after refactoring.
+ */
+ LocalCallingIdentity getCachedCallingIdentityForTranscoding(int uid) {
+ return getCachedCallingIdentityForFuse(uid);
+ }
+
@Deprecated
private String getSharedPackages() {
final String[] sharedPackageNames = mCallingIdentity.get().getSharedPackageNames();
@@ -4044,6 +4511,23 @@
private static final int TYPE_DELETE = 3;
/**
+ * Creating a new method for Transcoding to avoid any merge conflicts.
+ * TODO(b/170465810): Remove this when getQueryBuilder code is refactored.
+ */
+ @NonNull SQLiteQueryBuilder getQueryBuilderForTranscoding(int type, int match,
+ @NonNull Uri uri, @NonNull Bundle extras, @Nullable Consumer<String> honored) {
+ // Force MediaProvider calling identity when accessing the db from transcoding to avoid
+ // generating 'strict' SQL e.g forcing owner_package_name matches
+ // We already handle the required permission checks for the app before we get here
+ final LocalCallingIdentity token = clearLocalCallingIdentity();
+ try {
+ return getQueryBuilder(type, match, uri, extras, honored);
+ } finally {
+ restoreLocalCallingIdentity(token);
+ }
+ }
+
+ /**
* Generate a {@link SQLiteQueryBuilder} that is filtered based on the
* runtime permissions and/or {@link Uri} grants held by the caller.
* <ul>
@@ -4097,7 +4581,7 @@
final String volumeName = MediaStore.getVolumeName(uri);
final String includeVolumes;
if (MediaStore.VOLUME_EXTERNAL.equals(volumeName)) {
- includeVolumes = bindList(getExternalVolumeNames().toArray());
+ includeVolumes = bindList(mVolumeCache.getExternalVolumeNames().toArray());
} else {
includeVolumes = bindList(volumeName);
}
@@ -4105,7 +4589,18 @@
final String matchSharedPackagesClause = FileColumns.OWNER_PACKAGE_NAME + " IN "
+ sharedPackages;
- final boolean allowGlobal = checkCallingPermissionGlobal(uri, forWrite);
+ boolean allowGlobal;
+ final Uri redactedUri = extras.getParcelable(QUERY_ARG_REDACTED_URI);
+ if (redactedUri != null) {
+ if (forWrite) {
+ throw new UnsupportedOperationException(
+ "Writes on: " + redactedUri.toString() + " are not supported");
+ }
+ allowGlobal = checkCallingPermissionGlobal(redactedUri, false);
+ } else {
+ allowGlobal = checkCallingPermissionGlobal(uri, forWrite);
+ }
+
final boolean allowLegacy =
forWrite ? isCallingPackageLegacyWrite() : isCallingPackageLegacyRead();
final boolean allowLegacyRead = allowLegacy && !forWrite;
@@ -4139,8 +4634,7 @@
// Only accept ALL_VOLUMES parameter up until R, because we're not convinced we want
// to commit to this as an API.
- final boolean includeAllVolumes = (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) ?
- "1".equals(uri.getQueryParameter(ALL_VOLUMES)) : false;
+ final boolean includeAllVolumes = shouldIncludeRecentlyUnmountedVolumes(uri, extras);
final String callingPackage = getCallingPackageOrSelf();
switch (match) {
@@ -4385,8 +4879,8 @@
}
case AUDIO_ARTISTS_ID_ALBUMS: {
if (type == TYPE_QUERY) {
- qb.setTables("audio_albums");
- qb.setProjectionMap(getProjectionMap(Audio.Albums.class));
+ qb.setTables("audio_artists_albums");
+ qb.setProjectionMap(getProjectionMap(Audio.Artists.Albums.class));
final String artistId = uri.getPathSegments().get(3);
appendWhereStandalone(qb, "artist_id=?", artistId);
@@ -4618,6 +5112,36 @@
}
/**
+ * @return {@code true} if app requests to include database rows from
+ * recently unmounted volume.
+ * {@code false} otherwise.
+ */
+ private boolean shouldIncludeRecentlyUnmountedVolumes(Uri uri, Bundle extras) {
+ if (isFuseThread()) {
+ // File path requests don't require to query from unmounted volumes.
+ return false;
+ }
+
+ boolean isIncludeVolumesChangeEnabled = SdkLevel.isAtLeastS() &&
+ CompatChanges.isChangeEnabled(ENABLE_INCLUDE_ALL_VOLUMES, Binder.getCallingUid());
+ if ("1".equals(uri.getQueryParameter(ALL_VOLUMES))) {
+ // Support uri parameter only in R OS and below. Apps should use
+ // MediaStore#QUERY_ARG_RECENTLY_UNMOUNTED_VOLUMES on S OS onwards.
+ if (!isIncludeVolumesChangeEnabled) {
+ return true;
+ }
+ throw new IllegalArgumentException("Unsupported uri parameter \"all_volumes\"");
+ }
+ if (isIncludeVolumesChangeEnabled) {
+ // MediaStore#QUERY_ARG_INCLUDE_RECENTLY_UNMOUNTED_VOLUMES is only supported on S OS and
+ // for app targeting targetSdk>=S.
+ return extras.getBoolean(MediaStore.QUERY_ARG_INCLUDE_RECENTLY_UNMOUNTED_VOLUMES,
+ false);
+ }
+ return false;
+ }
+
+ /**
* Determine if given {@link Uri} has a
* {@link MediaColumns#OWNER_PACKAGE_NAME} column.
*/
@@ -4663,7 +5187,17 @@
private int deleteInternal(@NonNull Uri uri, @Nullable Bundle extras)
throws FallbackException {
+ final String volumeName = getVolumeName(uri);
+ PulledMetrics.logVolumeAccessViaMediaProvider(getCallingUidOrSelf(), volumeName);
+
extras = (extras != null) ? extras : new Bundle();
+ // REDACTED_URI_BUNDLE_KEY extra should only be set inside MediaProvider.
+ extras.remove(QUERY_ARG_REDACTED_URI);
+
+ if (isRedactedUri(uri)) {
+ // we don't support deletion on redacted uris.
+ return 0;
+ }
// INCLUDED_DEFAULT_DIRECTORIES extra should only be set inside MediaProvider.
extras.remove(INCLUDED_DEFAULT_DIRECTORIES);
@@ -4672,7 +5206,7 @@
final boolean allowHidden = isCallingPackageAllowedHidden();
final int match = matchUri(uri, allowHidden);
- switch(match) {
+ switch (match) {
case AUDIO_MEDIA_ID:
case AUDIO_PLAYLISTS_ID:
case VIDEO_MEDIA_ID:
@@ -4700,7 +5234,6 @@
int count = 0;
- final String volumeName = getVolumeName(uri);
final int targetSdkVersion = getCallingPackageTargetSdkVersion();
// handle MEDIA_SCANNER before calling getDatabaseForUri()
@@ -4781,6 +5314,8 @@
final int isDownload = c.getInt(3);
final String mimeType = c.getString(4);
+ // TODO(b/188782594) Consider logging mime type access on delete too.
+
// Forget that caller is owner of this item
mCallingIdentity.get().setOwned(id, false);
@@ -4793,8 +5328,6 @@
countPerMediaType[mediaType] += res;
}
- // Only need to inform DownloadProvider about the downloads deleted on
- // external volume.
if (isDownload == 1) {
deletedDownloadIds.put(id, mimeType);
}
@@ -4837,14 +5370,14 @@
}
if (deletedDownloadIds.size() > 0) {
- // Do this on a background thread, since we don't want to make binder
- // calls as part of a FUSE call.
- helper.postBackground(() -> {
- DownloadManager dm = getContext().getSystemService(DownloadManager.class);
- if (dm != null) {
- dm.onMediaStoreDownloadsDeleted(deletedDownloadIds);
- }
- });
+ notifyDownloadManagerOnDelete(helper, deletedDownloadIds);
+ }
+
+ // Check for other URI format grants for File API call only. Check right before
+ // returning count = 0, to leave positive cases performance unaffected.
+ if (count == 0 && isFuseThread()) {
+ count += deleteWithOtherUriGrants(uri, helper, projection, userWhere, userWhereArgs,
+ extras);
}
if (isFilesTable && !isCallingPackageSelf()) {
@@ -4856,6 +5389,54 @@
return count;
}
+ private int deleteWithOtherUriGrants(@NonNull Uri uri, DatabaseHelper helper,
+ String[] projection, String userWhere, String[] userWhereArgs,
+ @Nullable Bundle extras) {
+ try {
+ Cursor c = queryForSingleItemAsMediaProvider(uri, projection, userWhere, userWhereArgs,
+ null);
+ final int mediaType = c.getInt(0);
+ final String data = c.getString(1);
+ final long id = c.getLong(2);
+ final int isDownload = c.getInt(3);
+ final String mimeType = c.getString(4);
+
+ final Uri uriGranted = getOtherUriGrantsForPath(data, mediaType, Long.toString(id),
+ /* forWrite */ true);
+ if (uriGranted != null) {
+ // 1. delete file
+ deleteIfAllowed(uriGranted, extras, data);
+ // 2. delete file row from the db
+ final boolean allowHidden = isCallingPackageAllowedHidden();
+ final SQLiteQueryBuilder qb = getQueryBuilder(TYPE_DELETE,
+ matchUri(uriGranted, allowHidden), uriGranted, extras, null);
+ int count = qb.delete(helper, BaseColumns._ID + "=" + id, null);
+
+ if (isDownload == 1) {
+ final LongSparseArray<String> deletedDownloadIds = new LongSparseArray<>();
+ deletedDownloadIds.put(id, mimeType);
+ notifyDownloadManagerOnDelete(helper, deletedDownloadIds);
+ }
+ return count;
+ }
+ } catch (FileNotFoundException ignored) {
+ // Do nothing. Returns 0 files deleted.
+ }
+ return 0;
+ }
+
+ private void notifyDownloadManagerOnDelete(DatabaseHelper helper,
+ LongSparseArray<String> deletedDownloadIds) {
+ // Do this on a background thread, since we don't want to make binder
+ // calls as part of a FUSE call.
+ helper.postBackground(() -> {
+ DownloadManager dm = getContext().getSystemService(DownloadManager.class);
+ if (dm != null) {
+ dm.onMediaStoreDownloadsDeleted(deletedDownloadIds);
+ }
+ });
+ }
+
/**
* Executes identical delete repeatedly within a single transaction until
* stability is reached. Combined with {@link #ID_NOT_PARENT_CLAUSE}, this
@@ -4879,6 +5460,65 @@
});
}
+ @Nullable
+ @VisibleForTesting
+ Uri getRedactedUri(@NonNull Uri uri) {
+ if (!isUriSupportedForRedaction(uri)) {
+ return null;
+ }
+
+ DatabaseHelper helper;
+ try {
+ helper = getDatabaseForUri(uri);
+ } catch (VolumeNotFoundException e) {
+ throw e.rethrowAsIllegalArgumentException();
+ }
+
+ try (final Cursor c = helper.runWithoutTransaction(
+ (db) -> db.query("files",
+ new String[]{FileColumns.REDACTED_URI_ID}, FileColumns._ID + "=?",
+ new String[]{uri.getLastPathSegment()}, null, null, null))) {
+ // Database entry for uri not found.
+ if (!c.moveToFirst()) return null;
+
+ String redactedUriID = c.getString(c.getColumnIndex(FileColumns.REDACTED_URI_ID));
+ if (redactedUriID == null) {
+ // No redacted has even been created for this uri. Create a new redacted URI ID for
+ // the uri and store it in the DB.
+ redactedUriID = REDACTED_URI_ID_PREFIX + UUID.randomUUID().toString().replace("-",
+ "");
+
+ ContentValues cv = new ContentValues();
+ cv.put(FileColumns.REDACTED_URI_ID, redactedUriID);
+ int rowsAffected = helper.runWithTransaction(
+ (db) -> db.update("files", cv, FileColumns._ID + "=?",
+ new String[]{uri.getLastPathSegment()}));
+ if (rowsAffected == 0) {
+ // this shouldn't happen ideally, only reason this might happen is if the db
+ // entry got deleted in b/w in which case we should return null.
+ return null;
+ }
+ }
+
+ // Create and return a uri with ID = redactedUriID.
+ final Uri.Builder builder = ContentUris.removeId(uri).buildUpon();
+ builder.appendPath(redactedUriID);
+
+ return builder.build();
+ }
+ }
+
+ @NonNull
+ @VisibleForTesting
+ List<Uri> getRedactedUri(@NonNull List<Uri> uris) {
+ ArrayList<Uri> redactedUris = new ArrayList<>();
+ for (Uri uri : uris) {
+ redactedUris.add(getRedactedUri(uri));
+ }
+
+ return redactedUris;
+ }
+
@Override
public Bundle call(String method, String arg, Bundle extras) {
Trace.beginSection("call");
@@ -4925,6 +5565,7 @@
}
case MediaStore.SCAN_FILE_CALL:
case MediaStore.SCAN_VOLUME_CALL: {
+ final int userId = Binder.getCallingUid() / PER_USER_RANGE;
final LocalCallingIdentity token = clearLocalCallingIdentity();
final CallingIdentity providerToken = clearCallingIdentity();
try {
@@ -4937,7 +5578,13 @@
}
case MediaStore.SCAN_VOLUME_CALL: {
final String volumeName = arg;
- MediaService.onScanVolume(getContext(), volumeName, REASON_DEMAND);
+ try {
+ MediaVolume volume = mVolumeCache.findVolume(volumeName,
+ UserHandle.of(userId));
+ MediaService.onScanVolume(getContext(), volume, REASON_DEMAND);
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "Failed to find volume " + volumeName, e);
+ }
break;
}
}
@@ -5001,7 +5648,7 @@
try (ContentProviderClient client = getContext().getContentResolver()
.acquireUnstableContentProviderClient(
- MediaStore.EXTERNAL_STORAGE_PROVIDER_AUTHORITY)) {
+ getExternalStorageProviderAuthority())) {
extras.putParcelable(MediaStore.EXTRA_URI, fileUri);
return client.call(method, null, extras);
} catch (RemoteException e) {
@@ -5013,24 +5660,61 @@
getContext().enforceCallingUriPermission(documentUri,
Intent.FLAG_GRANT_READ_URI_PERMISSION, TAG);
- final Uri fileUri;
- try (ContentProviderClient client = getContext().getContentResolver()
- .acquireUnstableContentProviderClient(
- MediaStore.EXTERNAL_STORAGE_PROVIDER_AUTHORITY)) {
- final Bundle res = client.call(method, null, extras);
- fileUri = res.getParcelable(MediaStore.EXTRA_URI);
- } catch (RemoteException e) {
- throw new IllegalStateException(e);
+ final int callingPid = mCallingIdentity.get().pid;
+ final int callingUid = mCallingIdentity.get().uid;
+ final String callingPackage = getCallingPackage();
+ final CallingIdentity token = clearCallingIdentity();
+ final String authority = documentUri.getAuthority();
+
+ if (!authority.equals(MediaDocumentsProvider.AUTHORITY) &&
+ !authority.equals(DocumentsContract.EXTERNAL_STORAGE_PROVIDER_AUTHORITY)) {
+ throw new IllegalArgumentException("Provider for this Uri is not supported.");
}
- final LocalCallingIdentity token = clearLocalCallingIdentity();
- try {
+ try (ContentProviderClient client = getContext().getContentResolver()
+ .acquireUnstableContentProviderClient(authority)) {
+ final Bundle clientRes = client.call(method, null, extras);
+ final Uri fileUri = clientRes.getParcelable(MediaStore.EXTRA_URI);
final Bundle res = new Bundle();
- res.putParcelable(MediaStore.EXTRA_URI,
- queryForMediaUri(new File(fileUri.getPath()), null));
+ final Uri mediaStoreUri = fileUri.getAuthority().equals(MediaStore.AUTHORITY) ?
+ fileUri : queryForMediaUri(new File(fileUri.getPath()), null);
+ copyUriPermissionGrants(documentUri, mediaStoreUri, callingPid,
+ callingUid, callingPackage);
+ res.putParcelable(MediaStore.EXTRA_URI, mediaStoreUri);
return res;
} catch (FileNotFoundException e) {
throw new IllegalArgumentException(e);
+ } catch (RemoteException e) {
+ throw new IllegalStateException(e);
+ } finally {
+ restoreCallingIdentity(token);
+ }
+ }
+ case MediaStore.GET_REDACTED_MEDIA_URI_CALL: {
+ final Uri uri = extras.getParcelable(MediaStore.EXTRA_URI);
+ // NOTE: It is ok to update the DB and return a redacted URI for the cases when
+ // the user code only has read access, hence we don't check for write permission.
+ enforceCallingPermission(uri, Bundle.EMPTY, false);
+ final LocalCallingIdentity token = clearLocalCallingIdentity();
+ try {
+ final Bundle res = new Bundle();
+ res.putParcelable(MediaStore.EXTRA_URI, getRedactedUri(uri));
+ return res;
+ } finally {
+ restoreLocalCallingIdentity(token);
+ }
+ }
+ case MediaStore.GET_REDACTED_MEDIA_URI_LIST_CALL: {
+ final List<Uri> uris = extras.getParcelableArrayList(MediaStore.EXTRA_URI_LIST);
+ // NOTE: It is ok to update the DB and return a redacted URI for the cases when
+ // the user code only has read access, hence we don't check for write permission.
+ enforceCallingPermission(uris, false);
+ final LocalCallingIdentity token = clearLocalCallingIdentity();
+ try {
+ final Bundle res = new Bundle();
+ res.putParcelableArrayList(MediaStore.EXTRA_URI_LIST,
+ (ArrayList<? extends Parcelable>) getRedactedUri(uris));
+ return res;
} finally {
restoreLocalCallingIdentity(token);
}
@@ -5044,11 +5728,92 @@
res.putParcelable(MediaStore.EXTRA_RESULT, pi);
return res;
}
+ case MediaStore.GET_ORIGINAL_MEDIA_FORMAT_FILE_DESCRIPTOR_CALL: {
+ ParcelFileDescriptor inputPfd =
+ extras.getParcelable(MediaStore.EXTRA_FILE_DESCRIPTOR);
+ try {
+ File file = getFileFromFileDescriptor(inputPfd);
+ if (!mTranscodeHelper.supportsTranscode(file.getPath())) {
+ // Return an empty bundle instead of throwing an exception in the special
+ // case where the file does not support transcode. This avoids a misleading
+ // warning in android.database.DatabaseUtils#writeExceptionToParcel
+ //
+ // Note that we should be checking if a file is a modern format and not just
+ // that it supports transcoding, unfortunately, checking modern format
+ // requires either a db query or media scan which can lead to ANRs if apps
+ // or the system implicitly call this method as part of a
+ // MediaPlayer#setDataSource.
+ return new Bundle();
+ }
+
+ FuseDaemon fuseDaemon = getFuseDaemonForFile(file);
+ String outputPath = fuseDaemon.getOriginalMediaFormatFilePath(inputPfd);
+ if (TextUtils.isEmpty(outputPath)) {
+ throw new IllegalArgumentException(
+ "Invalid path for original media format file");
+ }
+
+ int posixMode = Os.fcntlInt(inputPfd.getFileDescriptor(), F_GETFL,
+ 0 /* args */);
+ int modeBits = FileUtils.translateModePosixToPfd(posixMode);
+ int uid = Binder.getCallingUid();
+
+ ParcelFileDescriptor outputPfd = openWithFuse(outputPath, uid,
+ 0 /* mediaCapabilitiesUid */, modeBits, true /* shouldRedact */,
+ false /* shouldTranscode */, 0 /* transcodeReason */);
+ Bundle res = new Bundle();
+ res.putParcelable(MediaStore.EXTRA_FILE_DESCRIPTOR, outputPfd);
+ return res;
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ } catch (ErrnoException e) {
+ throw new IllegalStateException(
+ "Failed to fetch access mode for file descriptor", e);
+ }
+ }
+ case MediaStore.IS_SYSTEM_GALLERY_CALL:
+ final LocalCallingIdentity token = clearLocalCallingIdentity();
+ try {
+ String packageName = arg;
+ int uid = extras.getInt(MediaStore.EXTRA_IS_SYSTEM_GALLERY_UID);
+ boolean isSystemGallery = PermissionUtils.checkWriteImagesOrVideoAppOps(
+ getContext(), uid, packageName, getContext().getAttributionTag());
+ Bundle res = new Bundle();
+ res.putBoolean(MediaStore.EXTRA_IS_SYSTEM_GALLERY_RESPONSE, isSystemGallery);
+ return res;
+ } finally {
+ restoreLocalCallingIdentity(token);
+ }
default:
throw new UnsupportedOperationException("Unsupported call: " + method);
}
}
+ /**
+ * Grant similar read/write access for mediaStoreUri as the caller has for documentsUri.
+ *
+ * Note: This function assumes that read permission check for documentsUri is already enforced.
+ * Note: This function currently does not check/grant for persisted Uris. Support for this can
+ * be added eventually, but the calling application will have to call
+ * ContentResolver#takePersistableUriPermission(Uri, int) for the mediaStoreUri to persist.
+ *
+ * @param documentsUri DocumentsProvider format content Uri
+ * @param mediaStoreUri MediaStore format content Uri
+ * @param callingPid pid of the caller
+ * @param callingUid uid of the caller
+ * @param callingPackage package name of the caller
+ */
+ private void copyUriPermissionGrants(Uri documentsUri, Uri mediaStoreUri,
+ int callingPid, int callingUid, String callingPackage) {
+ // No need to check for read permission, as we enforce it already.
+ int modeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION;
+ if (getContext().checkUriPermission(documentsUri, callingPid, callingUid,
+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == PERMISSION_GRANTED) {
+ modeFlags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
+ }
+ getContext().grantUriPermission(callingPackage, mediaStoreUri, modeFlags);
+ }
+
static List<Uri> collectUris(ClipData clipData) {
final ArrayList<Uri> res = new ArrayList<>();
for (int i = 0; i < clipData.getItemCount(); i++) {
@@ -5058,8 +5823,28 @@
}
/**
+ * Return the filesystem path of the real file on disk that is represented
+ * by the given {@link ParcelFileDescriptor}.
+ *
+ * Copied from {@link ParcelFileDescriptor#getFile}
+ */
+ private static File getFileFromFileDescriptor(ParcelFileDescriptor fileDescriptor)
+ throws IOException {
+ try {
+ final String path = Os.readlink("/proc/self/fd/" + fileDescriptor.getFd());
+ if (OsConstants.S_ISREG(Os.stat(path).st_mode)) {
+ return new File(path);
+ } else {
+ throw new IOException("Not a regular file: " + path);
+ }
+ } catch (ErrnoException e) {
+ throw e.rethrowAsIOException();
+ }
+ }
+
+ /**
* Generate the {@link PendingIntent} for the given grant request. This
- * method also sanity checks the incoming arguments for security purposes
+ * method also checks the incoming arguments for security purposes
* before creating the privileged {@link PendingIntent}.
*/
private @NonNull PendingIntent createRequest(@NonNull String method, @NonNull Bundle extras) {
@@ -5144,7 +5929,7 @@
* {@code ORDER BY} clauses.
*/
private @NonNull String ensureCustomCollator(@NonNull String locale) {
- // Quick sanity check that requested locale looks sane
+ // Quick check that requested locale looks reasonable
new ULocale(locale);
final String collationName = "custom_" + locale.replaceAll("[^a-zA-Z]", "");
@@ -5181,12 +5966,12 @@
final long[] knownIdsRaw = knownIds.toArray();
Arrays.sort(knownIdsRaw);
- for (String volumeName : getExternalVolumeNames()) {
+ for (MediaVolume volume : mVolumeCache.getExternalVolumes()) {
final List<File> thumbDirs;
try {
- thumbDirs = getThumbnailDirectories(volumeName);
+ thumbDirs = getThumbnailDirectories(volume);
} catch (FileNotFoundException e) {
- Log.w(TAG, "Failed to resolve volume " + volumeName, e);
+ Log.w(TAG, "Failed to resolve volume " + volume.getName(), e);
continue;
}
@@ -5328,8 +6113,8 @@
}
};
- private List<File> getThumbnailDirectories(String volumeName) throws FileNotFoundException {
- final File volumePath = getVolumePath(volumeName);
+ private List<File> getThumbnailDirectories(MediaVolume volume) throws FileNotFoundException {
+ final File volumePath = volume.getPath();
return Arrays.asList(
FileUtils.buildPath(volumePath, Environment.DIRECTORY_MUSIC, DIRECTORY_THUMBNAILS),
FileUtils.buildPath(volumePath, Environment.DIRECTORY_MOVIES, DIRECTORY_THUMBNAILS),
@@ -5406,7 +6191,17 @@
private int updateInternal(@NonNull Uri uri, @Nullable ContentValues initialValues,
@Nullable Bundle extras) throws FallbackException {
+ final String volumeName = getVolumeName(uri);
+ PulledMetrics.logVolumeAccessViaMediaProvider(getCallingUidOrSelf(), volumeName);
+
extras = (extras != null) ? extras : new Bundle();
+ // REDACTED_URI_BUNDLE_KEY extra should only be set inside MediaProvider.
+ extras.remove(QUERY_ARG_REDACTED_URI);
+
+ if (isRedactedUri(uri)) {
+ // we don't support update on redacted uris.
+ return 0;
+ }
// Related items are only considered for new media creation, and they
// can't be leveraged to move existing content into blocked locations
@@ -5434,7 +6229,6 @@
int count;
- final String volumeName = getVolumeName(uri);
final int targetSdkVersion = getCallingPackageTargetSdkVersion();
final boolean allowHidden = isCallingPackageAllowedHidden();
final int match = matchUri(uri, allowHidden);
@@ -5500,6 +6294,7 @@
boolean triggerInvalidate = false;
boolean triggerScan = false;
+ boolean isUriPublished = false;
if (initialValues != null) {
// IDs are forever; nobody should be editing them
initialValues.remove(MediaColumns._ID);
@@ -5586,7 +6381,7 @@
// make sure metadata is updated
if (MediaColumns.IS_PENDING.equals(column)) {
triggerScan = true;
-
+ isUriPublished = true;
// Explicitly clear columns used to ignore no-op scans,
// since we need to force a scan on publish
initialValues.putNull(MediaColumns.DATE_MODIFIED);
@@ -5760,8 +6555,10 @@
Trace.endSection();
}
- // Make sure any updated paths look sane
- assertFileColumnsSane(match, uri, initialValues);
+ assertPrivatePathNotInValues(initialValues);
+
+ // Make sure any updated paths look consistent
+ assertFileColumnsConsistent(match, uri, initialValues);
if (initialValues.containsKey(FileColumns.DATA)) {
// If we're changing paths, invalidate any thumbnails
@@ -5822,6 +6619,31 @@
}
}
+ boolean deferScan = false;
+ if (triggerScan) {
+ if (SdkLevel.isAtLeastS() &&
+ CompatChanges.isChangeEnabled(ENABLE_DEFERRED_SCAN, Binder.getCallingUid())) {
+ if (extras.containsKey(QUERY_ARG_DO_ASYNC_SCAN)) {
+ throw new IllegalArgumentException("Unsupported argument " +
+ QUERY_ARG_DO_ASYNC_SCAN + " used in extras");
+ }
+ deferScan = extras.getBoolean(QUERY_ARG_DEFER_SCAN, false);
+ if (deferScan && initialValues.containsKey(MediaColumns.IS_PENDING) &&
+ (initialValues.getAsInteger(MediaColumns.IS_PENDING) == 1)) {
+ // if the scan runs in async, ensure that the database row is excluded in
+ // default query until the metadata is updated by deferred scan.
+ // Apps will still be able to see this database row when queried with
+ // QUERY_ARG_MATCH_PENDING=MATCH_INCLUDE
+ values.put(FileColumns._MODIFIER, FileColumns._MODIFIER_CR_PENDING_METADATA);
+ qb.allowColumn(FileColumns._MODIFIER);
+ }
+ } else {
+ // Allow apps to use QUERY_ARG_DO_ASYNC_SCAN if the device is R or app is targeting
+ // targetSDK<=R.
+ deferScan = extras.getBoolean(QUERY_ARG_DO_ASYNC_SCAN, false);
+ }
+ }
+
count = updateAllowingReplace(qb, helper, values, userWhere, userWhereArgs);
// If the caller tried (and failed) to update metadata, the file on disk
@@ -5841,15 +6663,20 @@
try (Cursor c = queryForSingleItem(updatedUri,
new String[] { FileColumns.DATA }, null, null, null)) {
final File file = new File(c.getString(0));
- boolean runScanFileInBackground =
- extras.getBoolean(MediaStore.QUERY_ARG_DO_ASYNC_SCAN, false);
- if (runScanFileInBackground) {
+ final boolean notifyTranscodeHelper = isUriPublished;
+ if (deferScan) {
helper.postBackground(() -> {
scanFileAsMediaProvider(file, REASON_DEMAND);
+ if (notifyTranscodeHelper) {
+ notifyTranscodeHelperOnUriPublished(updatedUri);
+ }
});
} else {
helper.postBlocking(() -> {
scanFileAsMediaProvider(file, REASON_DEMAND);
+ if (notifyTranscodeHelper) {
+ notifyTranscodeHelperOnUriPublished(updatedUri);
+ }
});
}
} catch (Exception e) {
@@ -5866,6 +6693,29 @@
return count;
}
+ private void notifyTranscodeHelperOnUriPublished(Uri uri) {
+ BackgroundThread.getExecutor().execute(() -> {
+ final LocalCallingIdentity token = clearLocalCallingIdentity();
+ try {
+ mTranscodeHelper.onUriPublished(uri);
+ } finally {
+ restoreLocalCallingIdentity(token);
+ }
+ });
+ }
+
+ private void notifyTranscodeHelperOnFileOpen(String path, String ioPath, int uid,
+ int transformsReason) {
+ BackgroundThread.getExecutor().execute(() -> {
+ final LocalCallingIdentity token = clearLocalCallingIdentity();
+ try {
+ mTranscodeHelper.onFileOpen(path, ioPath, uid, transformsReason);
+ } finally {
+ restoreLocalCallingIdentity(token);
+ }
+ });
+ }
+
/**
* Update row(s) that match {@code userWhere} in MediaProvider database with {@code values}.
* Treats update as replace for updates with conflicts.
@@ -6238,17 +7088,25 @@
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
- return openFileCommon(uri, mode, null);
+ return openFileCommon(uri, mode, /*signal*/ null, /*opts*/ null);
}
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode, CancellationSignal signal)
throws FileNotFoundException {
- return openFileCommon(uri, mode, signal);
+ return openFileCommon(uri, mode, signal, /*opts*/ null);
}
- private ParcelFileDescriptor openFileCommon(Uri uri, String mode, CancellationSignal signal)
+ private ParcelFileDescriptor openFileCommon(Uri uri, String mode, CancellationSignal signal,
+ @Nullable Bundle opts)
throws FileNotFoundException {
+ opts = opts == null ? new Bundle() : opts;
+ // REDACTED_URI_BUNDLE_KEY extra should only be set inside MediaProvider.
+ opts.remove(QUERY_ARG_REDACTED_URI);
+ if (isRedactedUri(uri)) {
+ opts.putParcelable(QUERY_ARG_REDACTED_URI, uri);
+ uri = getUriForRedactedUri(uri);
+ }
uri = safeUncanonicalize(uri);
final boolean allowHidden = isCallingPackageAllowedHidden();
@@ -6256,34 +7114,40 @@
final String volumeName = getVolumeName(uri);
// Handle some legacy cases where we need to redirect thumbnails
- switch (match) {
- case AUDIO_ALBUMART_ID: {
- final long albumId = Long.parseLong(uri.getPathSegments().get(3));
- final Uri targetUri = ContentUris
- .withAppendedId(Audio.Albums.getContentUri(volumeName), albumId);
- return ensureThumbnail(targetUri, signal);
+ try {
+ switch (match) {
+ case AUDIO_ALBUMART_ID: {
+ final long albumId = Long.parseLong(uri.getPathSegments().get(3));
+ final Uri targetUri = ContentUris
+ .withAppendedId(Audio.Albums.getContentUri(volumeName), albumId);
+ return ensureThumbnail(targetUri, signal);
+ }
+ case AUDIO_ALBUMART_FILE_ID: {
+ final long audioId = Long.parseLong(uri.getPathSegments().get(3));
+ final Uri targetUri = ContentUris
+ .withAppendedId(Audio.Media.getContentUri(volumeName), audioId);
+ return ensureThumbnail(targetUri, signal);
+ }
+ case VIDEO_MEDIA_ID_THUMBNAIL: {
+ final long videoId = Long.parseLong(uri.getPathSegments().get(3));
+ final Uri targetUri = ContentUris
+ .withAppendedId(Video.Media.getContentUri(volumeName), videoId);
+ return ensureThumbnail(targetUri, signal);
+ }
+ case IMAGES_MEDIA_ID_THUMBNAIL: {
+ final long imageId = Long.parseLong(uri.getPathSegments().get(3));
+ final Uri targetUri = ContentUris
+ .withAppendedId(Images.Media.getContentUri(volumeName), imageId);
+ return ensureThumbnail(targetUri, signal);
+ }
}
- case AUDIO_ALBUMART_FILE_ID: {
- final long audioId = Long.parseLong(uri.getPathSegments().get(3));
- final Uri targetUri = ContentUris
- .withAppendedId(Audio.Media.getContentUri(volumeName), audioId);
- return ensureThumbnail(targetUri, signal);
- }
- case VIDEO_MEDIA_ID_THUMBNAIL: {
- final long videoId = Long.parseLong(uri.getPathSegments().get(3));
- final Uri targetUri = ContentUris
- .withAppendedId(Video.Media.getContentUri(volumeName), videoId);
- return ensureThumbnail(targetUri, signal);
- }
- case IMAGES_MEDIA_ID_THUMBNAIL: {
- final long imageId = Long.parseLong(uri.getPathSegments().get(3));
- final Uri targetUri = ContentUris
- .withAppendedId(Images.Media.getContentUri(volumeName), imageId);
- return ensureThumbnail(targetUri, signal);
- }
+ } finally {
+ // We have to log separately here because openFileAndEnforcePathPermissionsHelper calls
+ // a public MediaProvider API and so logs the access there.
+ PulledMetrics.logVolumeAccessViaMediaProvider(getCallingUidOrSelf(), volumeName);
}
- return openFileAndEnforcePathPermissionsHelper(uri, match, mode, signal);
+ return openFileAndEnforcePathPermissionsHelper(uri, match, mode, signal, opts);
}
@Override
@@ -6313,7 +7177,7 @@
}
// Worst case, return the underlying file
- return new AssetFileDescriptor(openFileCommon(uri, "r", signal), 0,
+ return new AssetFileDescriptor(openFileCommon(uri, "r", signal, opts), 0,
AssetFileDescriptor.UNKNOWN_LENGTH);
}
@@ -6528,12 +7392,36 @@
}
}
- private File getFuseFile(File file) {
+ public File getFuseFile(File file) {
String filePath = file.getPath().replaceFirst(
"/storage/", "/mnt/user/" + UserHandle.myUserId() + "/");
return new File(filePath);
}
+ private ParcelFileDescriptor openWithFuse(String filePath, int uid, int mediaCapabilitiesUid,
+ int modeBits, boolean shouldRedact, boolean shouldTranscode, int transcodeReason)
+ throws FileNotFoundException {
+ Log.d(TAG, "Open with FUSE. FilePath: " + filePath
+ + ". Uid: " + uid
+ + ". Media Capabilities Uid: " + mediaCapabilitiesUid
+ + ". ShouldRedact: " + shouldRedact
+ + ". ShouldTranscode: " + shouldTranscode);
+
+ int tid = android.os.Process.myTid();
+ synchronized (mPendingOpenInfo) {
+ mPendingOpenInfo.put(tid,
+ new PendingOpenInfo(uid, mediaCapabilitiesUid, shouldRedact, transcodeReason));
+ }
+
+ try {
+ return FileUtils.openSafely(getFuseFile(new File(filePath)), modeBits);
+ } finally {
+ synchronized (mPendingOpenInfo) {
+ mPendingOpenInfo.remove(tid);
+ }
+ }
+ }
+
private @NonNull FuseDaemon getFuseDaemonForFile(@NonNull File file)
throws FileNotFoundException {
final FuseDaemon daemon = ExternalStorageServiceImpl.getFuseDaemon(getVolumeId(file));
@@ -6572,10 +7460,16 @@
* a "/mnt/user" path.
*/
private ParcelFileDescriptor openFileAndEnforcePathPermissionsHelper(Uri uri, int match,
- String mode, CancellationSignal signal) throws FileNotFoundException {
+ String mode, CancellationSignal signal, @NonNull Bundle opts)
+ throws FileNotFoundException {
int modeBits = ParcelFileDescriptor.parseMode(mode);
boolean forWrite = (modeBits & ParcelFileDescriptor.MODE_WRITE_ONLY) != 0;
+ final Uri redactedUri = opts.getParcelable(QUERY_ARG_REDACTED_URI);
if (forWrite) {
+ if (redactedUri != null) {
+ throw new UnsupportedOperationException(
+ "Write is not supported on " + redactedUri.toString());
+ }
// Upgrade 'w' only to 'rw'. This allows us acquire a WR_LOCK when calling
// #shouldOpenWithFuse
modeBits |= ParcelFileDescriptor.MODE_READ_WRITE;
@@ -6607,7 +7501,11 @@
restoreLocalCallingIdentity(token);
}
- checkAccess(uri, Bundle.EMPTY, file, forWrite);
+ if (redactedUri == null) {
+ checkAccess(uri, Bundle.EMPTY, file, forWrite);
+ } else {
+ checkAccess(redactedUri, Bundle.EMPTY, file, false);
+ }
// We don't check ownership for files with IS_PENDING set by FUSE
if (isPending && !isPendingFromFuse(file)) {
@@ -6616,12 +7514,13 @@
final boolean callerIsOwner = Objects.equals(getCallingPackageOrSelf(), ownerPackageName);
// Figure out if we need to redact contents
- final boolean redactionNeeded = callerIsOwner ? false : isRedactionNeeded(uri);
+ final boolean redactionNeeded =
+ (redactedUri != null) || (!callerIsOwner && isRedactionNeeded(uri));
final RedactionInfo redactionInfo;
try {
redactionInfo = redactionNeeded ? getRedactionRanges(file)
: new RedactionInfo(new long[0], new long[0]);
- } catch(IOException e) {
+ } catch (IOException e) {
throw new IllegalStateException(e);
}
@@ -6661,33 +7560,23 @@
// First, handle any redaction that is needed for caller
final ParcelFileDescriptor pfd;
final String filePath = file.getPath();
+ final int uid = Binder.getCallingUid();
+ final int transcodeReason = mTranscodeHelper.shouldTranscode(filePath, uid, opts);
+ final boolean shouldTranscode = transcodeReason > 0;
+ int mediaCapabilitiesUid = opts.getInt(MediaStore.EXTRA_MEDIA_CAPABILITIES_UID);
+ if (!shouldTranscode || mediaCapabilitiesUid < Process.FIRST_APPLICATION_UID) {
+ // Although 0 is a valid UID, it's not a valid app uid.
+ // So, we use it to signify that mediaCapabilitiesUid is not set.
+ mediaCapabilitiesUid = 0;
+ }
if (redactionInfo.redactionRanges.length > 0) {
- if (SystemProperties.getBoolean(PROP_FUSE, false)) {
- // If fuse is enabled, we can provide an fd that points to the fuse
- // file system and handle redaction in the fuse handler when the caller reads.
- Log.i(TAG, "Redacting with new FUSE for " + filePath);
- long tid = android.os.Process.myTid();
- synchronized (mShouldRedactThreadIds) {
- mShouldRedactThreadIds.add(tid);
- }
- try {
- pfd = FileUtils.openSafely(getFuseFile(file), modeBits);
- } finally {
- synchronized (mShouldRedactThreadIds) {
- mShouldRedactThreadIds.remove(mShouldRedactThreadIds.indexOf(tid));
- }
- }
- } else {
- // TODO(b/135341978): Remove this and associated code
- // when fuse is on by default.
- Log.i(TAG, "Redacting with old FUSE for " + filePath);
- pfd = RedactingFileDescriptor.open(
- getContext(),
- file,
- modeBits,
- redactionInfo.redactionRanges,
- redactionInfo.freeOffsets);
- }
+ // If fuse is enabled, we can provide an fd that points to the fuse
+ // file system and handle redaction in the fuse handler when the caller reads.
+ pfd = openWithFuse(filePath, uid, mediaCapabilitiesUid, modeBits,
+ true /* shouldRedact */, shouldTranscode, transcodeReason);
+ } else if (shouldTranscode) {
+ pfd = openWithFuse(filePath, uid, mediaCapabilitiesUid, modeBits,
+ false /* shouldRedact */, shouldTranscode, transcodeReason);
} else {
FuseDaemon daemon = null;
try {
@@ -6698,22 +7587,23 @@
// Always acquire a readLock. This allows us make multiple opens via lower
// filesystem
boolean shouldOpenWithFuse = daemon != null
- && daemon.shouldOpenWithFuse(filePath, true /* forRead */, lowerFsFd.getFd());
+ && daemon.shouldOpenWithFuse(filePath, true /* forRead */,
+ lowerFsFd.getFd());
- if (SystemProperties.getBoolean(PROP_FUSE, false) && shouldOpenWithFuse) {
+ if (shouldOpenWithFuse) {
// If the file is already opened on the FUSE mount with VFS caching enabled
// we return an upper filesystem fd (via FUSE) to avoid file corruption
// resulting from cache inconsistencies between the upper and lower
// filesystem caches
- Log.w(TAG, "Using FUSE for " + filePath);
- pfd = FileUtils.openSafely(getFuseFile(file), modeBits);
+ pfd = openWithFuse(filePath, uid, mediaCapabilitiesUid, modeBits,
+ false /* shouldRedact */, shouldTranscode, transcodeReason);
try {
lowerFsFd.close();
} catch (IOException e) {
Log.w(TAG, "Failed to close lower filesystem fd " + file.getPath(), e);
}
} else {
- Log.i(TAG, "Using lower FS for " + filePath);
+ Log.i(TAG, "Open with lower FS for " + filePath + ". Uid: " + uid);
if (forWrite) {
// When opening for write on the lower filesystem, invalidate the VFS dentry
// so subsequent open/getattr calls will return correctly.
@@ -6793,6 +7683,27 @@
return mCallingIdentity.get().hasPermission(PERMISSION_IS_LEGACY_GRANTED);
}
+ private boolean shouldBypassDatabase(int uid) {
+ if (uid != android.os.Process.SHELL_UID && isCallingPackageManager()) {
+ return mCallingIdentity.get().shouldBypassDatabase(false /*isSystemGallery*/);
+ } else if (isCallingPackageSystemGallery()) {
+ if (isCallingPackageLegacyWrite()) {
+ // We bypass db operations for legacy system galleries with W_E_S (see b/167307393).
+ // Tracking a longer term solution in b/168784136.
+ return true;
+ } else if (isCallingPackageRequestingLegacy()) {
+ // If requesting legacy, app should have W_E_S along with SystemGallery appops.
+ return false;
+ } else if (!SdkLevel.isAtLeastS()) {
+ // We don't parse manifest flags for SdkLevel<=R yet. Hence, we don't bypass
+ // database updates for SystemGallery targeting R or above on R OS.
+ return false;
+ }
+ return mCallingIdentity.get().shouldBypassDatabase(true /*isSystemGallery*/);
+ }
+ return false;
+ }
+
private static int getFileMediaType(String path) {
final File file = new File(path);
final String mimeType = MimeUtils.resolveMimeType(file);
@@ -6872,16 +7783,7 @@
}
private boolean shouldBypassDatabaseAndSetDirtyForFuse(int uid, String path) {
- boolean shouldBypass = false;
- if (uid != android.os.Process.SHELL_UID && isCallingPackageManager()) {
- shouldBypass = true;
- } else if (isCallingPackageLegacyWrite() && isCallingPackageSystemGallery()) {
- // We bypass db operations for legacy system galleries with W_E_S (see b/167307393).
- // Tracking a longer term solution in b/168784136.
- shouldBypass = true;
- }
-
- if (shouldBypass) {
+ if (shouldBypassDatabase(uid)) {
synchronized (mNonHiddenPaths) {
File file = new File(path);
String key = file.getParent();
@@ -6896,8 +7798,9 @@
}
}
}
+ return true;
}
- return shouldBypass;
+ return false;
}
/**
@@ -6972,6 +7875,21 @@
}
}
+ private static final class PendingOpenInfo {
+ public final int uid;
+ public final int mediaCapabilitiesUid;
+ public final boolean shouldRedact;
+ public final int transcodeReason;
+
+ public PendingOpenInfo(int uid, int mediaCapabilitiesUid, boolean shouldRedact,
+ int transcodeReason) {
+ this.uid = uid;
+ this.mediaCapabilitiesUid = mediaCapabilitiesUid;
+ this.shouldRedact = shouldRedact;
+ this.transcodeReason = transcodeReason;
+ }
+ }
+
/**
* Calculates the ranges that need to be redacted for the given file and user that wants to
* access the file.
@@ -6982,44 +7900,51 @@
* @return Ranges that should be redacted.
*
* @throws IOException if an error occurs while calculating the redaction ranges
- *
- * Called from JNI in jni/MediaProviderWrapper.cpp
*/
- @Keep
@NonNull
- public long[] getRedactionRangesForFuse(String path, int uid, int tid) throws IOException {
- final File file = new File(path);
+ private long[] getRedactionRangesForFuse(String path, String ioPath, int original_uid, int uid,
+ int tid, boolean forceRedaction) throws IOException {
+ // |ioPath| might refer to a transcoded file path (which is not indexed in the db)
+ // |path| will always refer to a valid _data column
+ // We use |ioPath| for the filesystem access because in the case of transcoding,
+ // we want to get redaction ranges from the transcoded file and *not* the original file
+ final File file = new File(ioPath);
- // When we're calculating redaction ranges for MediaProvider, it means we're actually
- // calculating redaction ranges for another app that called to MediaProvider through Binder.
- // If the tid is in mShouldRedactThreadIds, we should redact, otherwise, we don't redact
- if (uid == android.os.Process.myUid()) {
- boolean shouldRedact = false;
- synchronized (mShouldRedactThreadIds) {
- shouldRedact = mShouldRedactThreadIds.indexOf(tid) != -1;
- }
- if (shouldRedact) {
- return getRedactionRanges(file).redactionRanges;
- } else {
- return new long[0];
+ if (forceRedaction) {
+ return getRedactionRanges(file).redactionRanges;
+ }
+
+ // When calculating redaction ranges initiated from MediaProvider, the redaction policy
+ // is slightly different from the FUSE initiated opens redaction policy. targetSdk=29 from
+ // MediaProvider requires redaction, but targetSdk=29 apps from FUSE don't require redaction
+ // Hence, we check the mPendingOpenInfo object (populated when opens are initiated from
+ // MediaProvider) if there's a pending open from MediaProvider with matching tid and uid and
+ // use the shouldRedact decision there if there's one.
+ synchronized (mPendingOpenInfo) {
+ PendingOpenInfo info = mPendingOpenInfo.get(tid);
+ if (info != null && info.uid == original_uid) {
+ boolean shouldRedact = info.shouldRedact;
+ if (shouldRedact) {
+ return getRedactionRanges(file).redactionRanges;
+ } else {
+ return new long[0];
+ }
}
}
final LocalCallingIdentity token =
clearLocalCallingIdentity(getCachedCallingIdentityForFuse(uid));
-
- long[] res = new long[0];
try {
if (!isRedactionNeeded()
|| shouldBypassFuseRestrictions(/*forWrite*/ false, path)) {
- return res;
+ return new long[0];
}
final Uri contentUri = FileUtils.getContentUriForPath(path);
final String[] projection = new String[]{
MediaColumns.OWNER_PACKAGE_NAME, MediaColumns._ID };
final String selection = MediaColumns.DATA + "=?";
- final String[] selectionArgs = new String[] { path };
+ final String[] selectionArgs = new String[]{path};
final String ownerPackageName;
final Uri item;
try (final Cursor c = queryForSingleItem(contentUri, projection, selection,
@@ -7038,17 +7963,22 @@
final boolean callerIsOwner = Objects.equals(getCallingPackageOrSelf(),
ownerPackageName);
+
+ if (callerIsOwner) {
+ return new long[0];
+ }
+
final boolean callerHasUriPermission = getContext().checkUriPermission(
item, mCallingIdentity.get().pid, mCallingIdentity.get().uid,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == PERMISSION_GRANTED;
-
- if (!callerIsOwner && !callerHasUriPermission) {
- res = getRedactionRanges(file).redactionRanges;
+ if (callerHasUriPermission) {
+ return new long[0];
}
+
+ return getRedactionRanges(file).redactionRanges;
} finally {
restoreLocalCallingIdentity(token);
}
- return res;
}
/**
@@ -7122,30 +8052,76 @@
* @param path the path of the file to be opened
* @param uid UID of the app requesting to open the file
* @param forWrite specifies if the file is to be opened for write
- * @return 0 upon success. {@link OsConstants#EACCES} if the operation is illegal or not
- * permitted for the given {@code uid} or if the calling package is a legacy app that doesn't
- * have right storage permission.
+ * @return {@link FileOpenResult} with {@code status} {@code 0} upon success and
+ * {@link FileOpenResult} with {@code status} {@link OsConstants#EACCES} if the operation is
+ * illegal or not permitted for the given {@code uid} or if the calling package is a legacy app
+ * that doesn't have right storage permission.
*
* Called from JNI in jni/MediaProviderWrapper.cpp
*/
@Keep
- public int isOpenAllowedForFuse(String path, int uid, boolean forWrite) {
+ public FileOpenResult onFileOpenForFuse(String path, String ioPath, int uid, int tid,
+ int transformsReason, boolean forWrite, boolean redact, boolean logTransformsMetrics) {
final LocalCallingIdentity token =
clearLocalCallingIdentity(getCachedCallingIdentityForFuse(uid));
+ PulledMetrics.logFileAccessViaFuse(getCallingUidOrSelf(), path);
+
+ boolean isSuccess = false;
+
+ final int originalUid = getBinderUidForFuse(uid, tid);
+ int mediaCapabilitiesUid = 0;
+ final PendingOpenInfo pendingOpenInfo;
+ synchronized (mPendingOpenInfo) {
+ pendingOpenInfo = mPendingOpenInfo.get(tid);
+ }
+
+ if (pendingOpenInfo != null && pendingOpenInfo.uid == originalUid) {
+ mediaCapabilitiesUid = pendingOpenInfo.mediaCapabilitiesUid;
+ }
+
try {
+ boolean forceRedaction = false;
+ String redactedUriId = null;
+ if (isSyntheticFilePathForRedactedUri(path, uid)) {
+ if (forWrite) {
+ // Redacted URIs are not allowed to update EXIF headers.
+ return new FileOpenResult(OsConstants.EACCES /* status */, originalUid,
+ mediaCapabilitiesUid, new long[0]);
+ }
+
+ redactedUriId = extractFileName(path);
+
+ // If path is redacted Uris' path, ioPath must be the real path, ioPath must
+ // haven been updated to the real path during onFileLookupForFuse.
+ path = ioPath;
+
+ // Irrespective of the permissions we want to redact in this case.
+ redact = true;
+ forceRedaction = true;
+ } else if (isSyntheticDirPath(path, uid)) {
+ // we don't support any other transformations under .transforms/synthetic dir
+ return new FileOpenResult(OsConstants.ENOENT /* status */, originalUid,
+ mediaCapabilitiesUid, new long[0]);
+ }
+
if (isPrivatePackagePathNotAccessibleByCaller(path)) {
Log.e(TAG, "Can't open a file in another app's external directory!");
- return OsConstants.ENOENT;
+ return new FileOpenResult(OsConstants.ENOENT, originalUid, mediaCapabilitiesUid,
+ new long[0]);
}
if (shouldBypassFuseRestrictions(forWrite, path)) {
- return 0;
+ isSuccess = true;
+ return new FileOpenResult(0 /* status */, originalUid, mediaCapabilitiesUid,
+ redact ? getRedactionRangesForFuse(path, ioPath, originalUid, uid, tid,
+ forceRedaction) : new long[0]);
}
// Legacy apps that made is this far don't have the right storage permission and hence
// are not allowed to access anything other than their external app directory
if (isCallingPackageRequestingLegacy()) {
- return OsConstants.EACCES;
+ return new FileOpenResult(OsConstants.EACCES /* status */, originalUid,
+ mediaCapabilitiesUid, new long[0]);
}
final Uri contentUri = FileUtils.getContentUriForPath(path);
@@ -7155,7 +8131,7 @@
MediaColumns.IS_PENDING,
FileColumns.MEDIA_TYPE};
final String selection = MediaColumns.DATA + "=?";
- final String[] selectionArgs = new String[]{ path };
+ final String[] selectionArgs = new String[]{path};
final long id;
final int mediaType;
final boolean isPending;
@@ -7169,7 +8145,7 @@
mediaType = c.getInt(3);
}
final File file = new File(path);
- final Uri fileUri = MediaStore.Files.getContentUri(extractVolumeName(path), id);
+ Uri fileUri = MediaStore.Files.getContentUri(extractVolumeName(path), id);
// We don't check ownership for files with IS_PENDING set by FUSE
if (isPending && !isPendingFromFuse(new File(path))) {
requireOwnershipForItem(ownerPackageName, fileUri);
@@ -7183,63 +8159,91 @@
try {
// checkAccess throws FileNotFoundException only from checkWorldReadAccess(),
// which we already check above. Hence, handling only SecurityException.
+ if (redactedUriId != null) {
+ fileUri = ContentUris.removeId(fileUri).buildUpon().appendPath(
+ redactedUriId).build();
+ }
checkAccess(fileUri, Bundle.EMPTY, file, forWrite);
} catch (SecurityException e) {
// Check for other Uri formats only when the single uri check flow fails.
// Throw the previous exception if the multi-uri checks failed.
- if (!(isFilePathSupportForMediaUris() &&
- hasOtherUriGrants(path, mediaType, id, forWrite))) {
+ final String uriId = redactedUriId == null ? Long.toString(id) : redactedUriId;
+ if (getOtherUriGrantsForPath(path, mediaType, uriId, forWrite) == null) {
throw e;
}
}
- return 0;
- } catch (FileNotFoundException e) {
- // We are here because there is no db row corresponding to the requested path.
- Log.e(TAG, "Couldn't find file: " + path);
- return OsConstants.EACCES;
+ isSuccess = true;
+ return new FileOpenResult(0 /* status */, originalUid, mediaCapabilitiesUid,
+ redact ? getRedactionRangesForFuse(path, ioPath, originalUid, uid, tid,
+ forceRedaction) : new long[0]);
+ } catch (IOException e) {
+ // We are here because
+ // * There is no db row corresponding to the requested path, which is more unlikely.
+ // * getRedactionRangesForFuse couldn't fetch the redaction info correctly
+ // In all of these cases, it means that app doesn't have access permission to the file.
+ Log.e(TAG, "Couldn't find file: " + path, e);
+ return new FileOpenResult(OsConstants.EACCES /* status */, originalUid,
+ mediaCapabilitiesUid, new long[0]);
} catch (IllegalStateException | SecurityException e) {
Log.e(TAG, "Permission to access file: " + path + " is denied");
- return OsConstants.EACCES;
+ return new FileOpenResult(OsConstants.EACCES /* status */, originalUid,
+ mediaCapabilitiesUid, new long[0]);
} finally {
+ if (isSuccess && logTransformsMetrics) {
+ notifyTranscodeHelperOnFileOpen(path, ioPath, originalUid, transformsReason);
+ }
restoreLocalCallingIdentity(token);
}
}
- private boolean hasOtherUriGrants(String path, int mediaType, long id, boolean forWrite) {
- Set<Uri> otherUris = new ArraySet<Uri>();
+ private @Nullable Uri getOtherUriGrantsForPath(String path, boolean forWrite) {
+ final Uri contentUri = FileUtils.getContentUriForPath(path);
+ final String[] projection = new String[]{
+ MediaColumns._ID,
+ FileColumns.MEDIA_TYPE};
+ final String selection = MediaColumns.DATA + "=?";
+ final String[] selectionArgs = new String[]{path};
+ final String id;
+ final int mediaType;
+ try (final Cursor c = queryForSingleItemAsMediaProvider(contentUri, projection, selection,
+ selectionArgs, null)) {
+ id = c.getString(0);
+ mediaType = c.getInt(1);
+ return getOtherUriGrantsForPath(path, mediaType, id, forWrite);
+ } catch (FileNotFoundException ignored) {
+ }
+ return null;
+ }
+
+ @Nullable
+ private Uri getOtherUriGrantsForPath(String path, int mediaType, String id, boolean forWrite) {
+ List<Uri> otherUris = new ArrayList<Uri>();
final Uri mediaUri = getMediaUriForFuse(extractVolumeName(path), mediaType, id);
otherUris.add(mediaUri);
final Uri externalMediaUri = getMediaUriForFuse(MediaStore.VOLUME_EXTERNAL, mediaType, id);
otherUris.add(externalMediaUri);
- return bulkCheckUriPermissions(otherUris, forWrite);
+ return getPermissionGrantedUri(otherUris, forWrite);
}
- private @NonNull Uri getMediaUriForFuse(@NonNull String volumeName, int mediaType, long id) {
+ @NonNull
+ private Uri getMediaUriForFuse(@NonNull String volumeName, int mediaType, String id) {
+ Uri uri = MediaStore.Files.getContentUri(volumeName);
switch (mediaType) {
case FileColumns.MEDIA_TYPE_IMAGE:
- return MediaStore.Images.Media.getContentUri(volumeName, id);
+ uri = MediaStore.Images.Media.getContentUri(volumeName);
+ break;
case FileColumns.MEDIA_TYPE_VIDEO:
- return MediaStore.Video.Media.getContentUri(volumeName, id);
+ uri = MediaStore.Video.Media.getContentUri(volumeName);
+ break;
case FileColumns.MEDIA_TYPE_AUDIO:
- return MediaStore.Audio.Media.getContentUri(volumeName, id);
+ uri = MediaStore.Audio.Media.getContentUri(volumeName);
+ break;
case FileColumns.MEDIA_TYPE_PLAYLIST:
- return ContentUris.withAppendedId(
- MediaStore.Audio.Playlists.getContentUri(volumeName), id);
- default:
- // return files URIs
- return MediaStore.Files.getContentUri(volumeName, id);
+ uri = MediaStore.Audio.Playlists.getContentUri(volumeName);
+ break;
}
- }
- /**
- * Feature flag to support File APIs for different formats of media-store URI grants like:
- * * content://media/external_primary/images/media/123
- * * content://media/external/images/media/123
- *
- * Default value: false
- */
- private boolean isFilePathSupportForMediaUris() {
- return SystemProperties.getBoolean("sys.filepathsupport.mediauri", false);
+ return uri.buildUpon().appendPath(id).build();
}
/**
@@ -7284,6 +8288,7 @@
case DIRECTORY_ALARMS_LOWER_CASE:
case DIRECTORY_NOTIFICATIONS_LOWER_CASE:
case DIRECTORY_AUDIOBOOKS_LOWER_CASE:
+ case DIRECTORY_RECORDINGS_LOWER_CASE:
uri = Audio.Media.getContentUri(volName);
break;
case DIRECTORY_MUSIC_LOWER_CASE:
@@ -7374,7 +8379,7 @@
/**
* Enforces file creation restrictions (see return values) for the given file on behalf of the
- * app with the given {@code uid}. If the file is is added to the shared storage, creates a
+ * app with the given {@code uid}. If the file is added to the shared storage, creates a
* database entry for it.
* <p> Does NOT create file.
*
@@ -7398,6 +8403,7 @@
public int insertFileIfNecessaryForFuse(@NonNull String path, int uid) {
final LocalCallingIdentity token =
clearLocalCallingIdentity(getCachedCallingIdentityForFuse(uid));
+ PulledMetrics.logFileAccessViaFuse(getCallingUidOrSelf(), path);
try {
if (isPrivatePackagePathNotAccessibleByCaller(path)) {
@@ -7523,6 +8529,8 @@
public int deleteFileForFuse(@NonNull String path, int uid) throws IOException {
final LocalCallingIdentity token =
clearLocalCallingIdentity(getCachedCallingIdentityForFuse(uid));
+ PulledMetrics.logFileAccessViaFuse(getCallingUidOrSelf(), path);
+
try {
if (isPrivatePackagePathNotAccessibleByCaller(path)) {
Log.e(TAG, "Can't delete a file in another app's external directory!");
@@ -7585,6 +8593,7 @@
@NonNull String path, int uid, boolean forCreate) {
final LocalCallingIdentity token =
clearLocalCallingIdentity(getCachedCallingIdentityForFuse(uid));
+ PulledMetrics.logFileAccessViaFuse(getCallingUidOrSelf(), path);
try {
// App dirs are not indexed, so we don't create an entry for the file.
@@ -7638,6 +8647,7 @@
public int isOpendirAllowedForFuse(@NonNull String path, int uid, boolean forWrite) {
final LocalCallingIdentity token =
clearLocalCallingIdentity(getCachedCallingIdentityForFuse(uid));
+ PulledMetrics.logFileAccessViaFuse(getCallingUidOrSelf(), path);
try {
if ("/storage/emulated".equals(path)) {
return OsConstants.EPERM;
@@ -7739,6 +8749,30 @@
return mCallingIdentity.get().hasPermission(APPOP_REQUEST_INSTALL_PACKAGES_FOR_SHARED_UID);
}
+ private String getExternalStorageProviderAuthority() {
+ if (SdkLevel.isAtLeastS()) {
+ return getExternalStorageProviderAuthorityFromDocumentsContract();
+ }
+ return MediaStore.EXTERNAL_STORAGE_PROVIDER_AUTHORITY;
+ }
+
+ @RequiresApi(Build.VERSION_CODES.S)
+ private String getExternalStorageProviderAuthorityFromDocumentsContract() {
+ return DocumentsContract.EXTERNAL_STORAGE_PROVIDER_AUTHORITY;
+ }
+
+ private String getDownloadsProviderAuthority() {
+ if (SdkLevel.isAtLeastS()) {
+ return getDownloadsProviderAuthorityFromDocumentsContract();
+ }
+ return DOWNLOADS_PROVIDER_AUTHORITY;
+ }
+
+ @RequiresApi(Build.VERSION_CODES.S)
+ private String getDownloadsProviderAuthorityFromDocumentsContract() {
+ return DocumentsContract.EXTERNAL_STORAGE_PROVIDER_AUTHORITY;
+ }
+
private boolean isCallingIdentityDownloadProvider(int uid) {
return uid == mDownloadsAuthorityAppId;
}
@@ -7755,9 +8789,9 @@
* The following apps have access to all private-app directories on secondary volumes:
* * ExternalStorageProvider
* * DownloadProvider
- * * Signature/privileged apps with ACCESS_MTP permission granted
- * (TODO(b/175796984): Allow *only* signature apps with ACCESS_MTP to access all
- * private-app directories).
+ * * Signature apps with ACCESS_MTP permission granted
+ * (Note: For Android R we also allow privileged apps with ACCESS_MTP to access all
+ * private-app directories, this additional access is removed for Android S+).
*
* Installer apps can only access private-app directories on Android/obb.
*
@@ -7768,16 +8802,43 @@
final LocalCallingIdentity token =
clearLocalCallingIdentity(getCachedCallingIdentityForFuse(uid));
try {
- if (isCallingIdentityDownloadProvider(uid) ||
- isCallingIdentityExternalStorageProvider(uid) || isCallingIdentityMtp(uid)) {
- return true;
+ if (SdkLevel.isAtLeastS()) {
+ return isMountModeAllowedPrivatePathAccess(uid, getCallingPackage(), path);
+ } else {
+ if (isCallingIdentityDownloadProvider(uid) ||
+ isCallingIdentityExternalStorageProvider(uid) || isCallingIdentityMtp(
+ uid)) {
+ return true;
+ }
+ return (isObbOrChildPath(path) && isCallingIdentityAllowedInstallerAccess(uid));
}
- return (isObbOrChildPath(path) && isCallingIdentityAllowedInstallerAccess(uid));
} finally {
restoreLocalCallingIdentity(token);
}
}
+ @RequiresApi(Build.VERSION_CODES.S)
+ private boolean isMountModeAllowedPrivatePathAccess(int uid, String packageName, String path) {
+ // This is required as only MediaProvider (package with WRITE_MEDIA_STORAGE) can access
+ // mount modes.
+ final CallingIdentity token = clearCallingIdentity();
+ try {
+ final int mountMode = mStorageManager.getExternalStorageMountMode(uid, packageName);
+ switch (mountMode) {
+ case StorageManager.MOUNT_MODE_EXTERNAL_ANDROID_WRITABLE:
+ case StorageManager.MOUNT_MODE_EXTERNAL_PASS_THROUGH:
+ return true;
+ case StorageManager.MOUNT_MODE_EXTERNAL_INSTALLER:
+ return isObbOrChildPath(path);
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "Caller does not have the permissions to access mount modes: ", e);
+ } finally {
+ restoreCallingIdentity(token);
+ }
+ return false;
+ }
+
private boolean checkCallingPermissionGlobal(Uri uri, boolean forWrite) {
// System internals can work with all media
if (isCallingPackageSelf() || isCallingPackageShell()) {
@@ -7808,20 +8869,45 @@
return isUriPermissionGranted(uri, forWrite);
}
- private boolean bulkCheckUriPermissions(Set<Uri> uris, boolean forWrite) {
- for (Uri uri : uris) {
- if (isUriPermissionGranted(uri, forWrite)) {
- return true;
+ /**
+ * Returns any uri that is granted from the set of Uris passed.
+ */
+ private @Nullable Uri getPermissionGrantedUri(@NonNull List<Uri> uris, boolean forWrite) {
+ if (SdkLevel.isAtLeastS()) {
+ int[] res = checkUriPermissions(uris, mCallingIdentity.get().pid,
+ mCallingIdentity.get().uid, forWrite);
+ if (res.length != uris.size()) {
+ return null;
+ }
+ for (int i = 0; i < uris.size(); i++) {
+ if (res[i] == PERMISSION_GRANTED) {
+ return uris.get(i);
+ }
+ }
+ } else {
+ for (Uri uri : uris) {
+ if (isUriPermissionGranted(uri, forWrite)) {
+ return uri;
+ }
}
}
- return false;
+ return null;
+ }
+
+ @RequiresApi(Build.VERSION_CODES.S)
+ private int[] checkUriPermissions(@NonNull List<Uri> uris, int pid, int uid, boolean forWrite) {
+ final int modeFlags = forWrite
+ ? Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+ : Intent.FLAG_GRANT_READ_URI_PERMISSION;
+ return getContext().checkUriPermissions(uris, pid, uid, modeFlags);
}
private boolean isUriPermissionGranted(Uri uri, boolean forWrite) {
+ final int modeFlags = forWrite
+ ? Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+ : Intent.FLAG_GRANT_READ_URI_PERMISSION;
int uriPermission = getContext().checkUriPermission(uri, mCallingIdentity.get().pid,
- mCallingIdentity.get().uid, forWrite
- ? Intent.FLAG_GRANT_WRITE_URI_PERMISSION
- : Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ mCallingIdentity.get().uid, modeFlags);
return uriPermission == PERMISSION_GRANTED;
}
@@ -7830,6 +8916,45 @@
return FuseDaemon.native_is_fuse_thread();
}
+ @VisibleForTesting
+ public boolean getBooleanDeviceConfig(String key, boolean defaultValue) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT, key,
+ defaultValue);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @VisibleForTesting
+ public int getIntDeviceConfig(String key, int defaultValue) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return DeviceConfig.getInt(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT, key,
+ defaultValue);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @VisibleForTesting
+ public String getStringDeviceConfig(String key, String defaultValue) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return DeviceConfig.getString(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT, key,
+ defaultValue);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @VisibleForTesting
+ public void addOnPropertiesChangedListener(OnPropertiesChangedListener listener) {
+ DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ BackgroundThread.getExecutor(), listener);
+ }
+
@Deprecated
private boolean checkCallingPermissionAudio(boolean forWrite, String callingPackage) {
if (forWrite) {
@@ -7878,6 +9003,12 @@
}
}
+ private void enforceCallingPermission(@NonNull Collection<Uri> uris, boolean forWrite) {
+ for (Uri uri : uris) {
+ enforceCallingPermission(uri, Bundle.EMPTY, forWrite);
+ }
+ }
+
private void enforceCallingPermissionInternal(@NonNull Uri uri, @NonNull Bundle extras,
boolean forWrite) {
Objects.requireNonNull(uri);
@@ -7890,6 +9021,16 @@
return;
}
+ // For redacted URI proceed with its corresponding URI as query builder doesn't support
+ // redacted URIs for fetching a database row
+ // NOTE: The grants (if any) must have been on redacted URI hence global check requires
+ // redacted URI
+ Uri redactedUri = null;
+ if (isRedactedUri(uri)) {
+ redactedUri = uri;
+ uri = getUriForRedactedUri(uri);
+ }
+
final DatabaseHelper helper;
try {
helper = getDatabaseForUri(uri);
@@ -7955,6 +9096,7 @@
}
}
+ if (redactedUri != null) uri = redactedUri;
throw new SecurityException(getCallingPackageOrSelf() + " has no access to " + uri);
}
@@ -7978,7 +9120,7 @@
// First, does caller have the needed row-level access?
enforceCallingPermission(uri, extras, isWrite);
- // Second, does the path look sane?
+ // Second, does the path look consistent?
if (!FileUtils.contains(Environment.getStorageDirectory(), file)) {
checkWorldReadAccess(file.getAbsolutePath());
}
@@ -8115,10 +9257,27 @@
}
}
+ /**
+ * Creating a new method for Transcoding to avoid any merge conflicts.
+ * TODO(b/170465810): Remove this when the code is refactored.
+ */
+ @NonNull DatabaseHelper getDatabaseForUriForTranscoding(Uri uri)
+ throws VolumeNotFoundException {
+ return getDatabaseForUri(uri);
+ }
+
private @NonNull DatabaseHelper getDatabaseForUri(Uri uri) throws VolumeNotFoundException {
final String volumeName = resolveVolumeName(uri);
- synchronized (mAttachedVolumeNames) {
- if (!mAttachedVolumeNames.contains(volumeName)) {
+ synchronized (mAttachedVolumes) {
+ boolean volumeAttached = false;
+ UserHandle user = mCallingIdentity.get().getUser();
+ for (MediaVolume vol : mAttachedVolumes) {
+ if (vol.getName().equals(volumeName) && vol.isVisibleToUser(user)) {
+ volumeAttached = true;
+ break;
+ }
+ }
+ if (!volumeAttached) {
throw new VolumeNotFoundException(volumeName);
}
}
@@ -8153,42 +9312,43 @@
return MediaStore.AUTHORITY_URI.buildUpon().appendPath(volumeName).build();
}
- public Uri attachVolume(String volume, boolean validate) {
+ public Uri attachVolume(MediaVolume volume, boolean validate) {
if (mCallingIdentity.get().pid != android.os.Process.myPid()) {
throw new SecurityException(
"Opening and closing databases not allowed.");
}
- // Quick sanity check for shady volume names
- MediaStore.checkArgumentVolumeName(volume);
+ final String volumeName = volume.getName();
- // Quick sanity check that volume actually exists
- if (!MediaStore.VOLUME_INTERNAL.equals(volume) && validate) {
+ // Quick check for shady volume names
+ MediaStore.checkArgumentVolumeName(volumeName);
+
+ // Quick check that volume actually exists
+ if (!MediaStore.VOLUME_INTERNAL.equals(volumeName) && validate) {
try {
- getVolumePath(volume);
+ getVolumePath(volumeName);
} catch (IOException e) {
throw new IllegalArgumentException(
"Volume " + volume + " currently unavailable", e);
}
}
- synchronized (mAttachedVolumeNames) {
- mAttachedVolumeNames.add(volume);
+ synchronized (mAttachedVolumes) {
+ mAttachedVolumes.add(volume);
}
final ContentResolver resolver = getContext().getContentResolver();
- final Uri uri = getBaseContentUri(volume);
- resolver.notifyChange(getBaseContentUri(volume), null);
+ final Uri uri = getBaseContentUri(volumeName);
+ // TODO(b/182396009) we probably also want to notify clone profile (and vice versa)
+ resolver.notifyChange(getBaseContentUri(volumeName), null);
if (LOGV) Log.v(TAG, "Attached volume: " + volume);
- if (!MediaStore.VOLUME_INTERNAL.equals(volume)) {
+ if (!MediaStore.VOLUME_INTERNAL.equals(volumeName)) {
// Also notify on synthetic view of all devices
resolver.notifyChange(getBaseContentUri(MediaStore.VOLUME_EXTERNAL), null);
ForegroundThread.getExecutor().execute(() -> {
- final DatabaseHelper helper = MediaStore.VOLUME_INTERNAL.equals(volume)
- ? mInternalDatabase : mExternalDatabase;
- helper.runWithTransaction((db) -> {
+ mExternalDatabase.runWithTransaction((db) -> {
ensureDefaultFolders(volume, db);
ensureThumbnailsValid(volume, db);
return null;
@@ -8197,26 +9357,33 @@
// We just finished the database operation above, we know that
// it's ready to answer queries, so notify our DocumentProvider
// so it can answer queries without risking ANR
- MediaDocumentsProvider.onMediaStoreReady(getContext(), volume);
+ MediaDocumentsProvider.onMediaStoreReady(getContext(), volumeName);
});
}
return uri;
}
private void detachVolume(Uri uri) {
- detachVolume(MediaStore.getVolumeName(uri));
+ final String volumeName = MediaStore.getVolumeName(uri);
+ try {
+ detachVolume(getVolume(volumeName));
+ } catch (FileNotFoundException e) {
+ Log.e(TAG, "Couldn't find volume for URI " + uri, e) ;
+ }
}
- public void detachVolume(String volume) {
+ public void detachVolume(MediaVolume volume) {
if (mCallingIdentity.get().pid != android.os.Process.myPid()) {
throw new SecurityException(
"Opening and closing databases not allowed.");
}
- // Quick sanity check for shady volume names
- MediaStore.checkArgumentVolumeName(volume);
+ final String volumeName = volume.getName();
- if (MediaStore.VOLUME_INTERNAL.equals(volume)) {
+ // Quick check for shady volume names
+ MediaStore.checkArgumentVolumeName(volumeName);
+
+ if (MediaStore.VOLUME_INTERNAL.equals(volumeName)) {
throw new UnsupportedOperationException(
"Deleting the internal volume is not allowed");
}
@@ -8224,24 +9391,24 @@
// Signal any scanning to shut down
mMediaScanner.onDetachVolume(volume);
- synchronized (mAttachedVolumeNames) {
- mAttachedVolumeNames.remove(volume);
+ synchronized (mAttachedVolumes) {
+ mAttachedVolumes.remove(volume);
}
final ContentResolver resolver = getContext().getContentResolver();
- final Uri uri = getBaseContentUri(volume);
- resolver.notifyChange(getBaseContentUri(volume), null);
+ final Uri uri = getBaseContentUri(volumeName);
+ resolver.notifyChange(getBaseContentUri(volumeName), null);
- if (!MediaStore.VOLUME_INTERNAL.equals(volume)) {
+ if (!MediaStore.VOLUME_INTERNAL.equals(volumeName)) {
// Also notify on synthetic view of all devices
resolver.notifyChange(getBaseContentUri(MediaStore.VOLUME_EXTERNAL), null);
}
- if (LOGV) Log.v(TAG, "Detached volume: " + volume);
+ if (LOGV) Log.v(TAG, "Detached volume: " + volumeName);
}
- @GuardedBy("mAttachedVolumeNames")
- private final ArraySet<String> mAttachedVolumeNames = new ArraySet<>();
+ @GuardedBy("mAttachedVolumes")
+ private final ArraySet<MediaVolume> mAttachedVolumes = new ArraySet<>();
@GuardedBy("mCustomCollators")
private final ArraySet<String> mCustomCollators = new ArraySet<>();
@@ -8249,6 +9416,7 @@
private DatabaseHelper mInternalDatabase;
private DatabaseHelper mExternalDatabase;
+ private TranscodeHelper mTranscodeHelper;
// name of the volume currently being scanned by the media scanner (or null)
private String mMediaScannerVolume;
@@ -8306,6 +9474,9 @@
static final int DOWNLOADS = 800;
static final int DOWNLOADS_ID = 801;
+ 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));
+
private LocalUriMatcher mUriMatcher;
private static final String[] PATH_PROJECTION = new String[] {
@@ -8518,6 +9689,10 @@
return mCallingIdentity.get().hasPermission(PERMISSION_IS_SYSTEM_GALLERY);
}
+ private int getCallingUidOrSelf() {
+ return mCallingIdentity.get().uid;
+ }
+
@Deprecated
private String getCallingPackageOrSelf() {
return mCallingIdentity.get().getPackageName();
@@ -8567,11 +9742,14 @@
@Override
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
writer.println("mThumbSize=" + mThumbSize);
- synchronized (mAttachedVolumeNames) {
- writer.println("mAttachedVolumeNames=" + mAttachedVolumeNames);
+ synchronized (mAttachedVolumes) {
+ writer.println("mAttachedVolumes=" + mAttachedVolumes);
}
writer.println();
+ mTranscodeHelper.dump(writer);
+ writer.println();
+
Logging.dumpPersistent(writer);
}
}
diff --git a/src/com/android/providers/media/MediaService.java b/src/com/android/providers/media/MediaService.java
index d7c6bab..bc7330a 100644
--- a/src/com/android/providers/media/MediaService.java
+++ b/src/com/android/providers/media/MediaService.java
@@ -27,7 +27,10 @@
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
+import android.os.Bundle;
import android.os.Trace;
+import android.os.UserHandle;
+import android.os.storage.StorageVolume;
import android.provider.MediaStore;
import android.util.Log;
@@ -41,6 +44,21 @@
public class MediaService extends JobIntentService {
private static final int JOB_ID = -300;
+ private static final String ACTION_SCAN_VOLUME
+ = "com.android.providers.media.action.SCAN_VOLUME";
+
+ private static final String EXTRA_MEDIAVOLUME = "MediaVolume";
+
+ private static final String EXTRA_SCAN_REASON = "scan_reason";
+
+
+ public static void queueVolumeScan(Context context, MediaVolume volume, int reason) {
+ Intent intent = new Intent(ACTION_SCAN_VOLUME);
+ intent.putExtra(EXTRA_MEDIAVOLUME, volume) ;
+ intent.putExtra(EXTRA_SCAN_REASON, reason);
+ enqueueWork(context, intent);
+ }
+
public static void enqueueWork(Context context, Intent work) {
enqueueWork(context, MediaService.class, JOB_ID, work);
}
@@ -67,8 +85,10 @@
onScanFile(this, intent.getData());
break;
}
- case Intent.ACTION_MEDIA_MOUNTED: {
- onScanVolume(this, intent.getData(), REASON_MOUNTED);
+ case ACTION_SCAN_VOLUME: {
+ final MediaVolume volume = intent.getParcelableExtra(EXTRA_MEDIAVOLUME);
+ int reason = intent.getIntExtra(EXTRA_SCAN_REASON, REASON_DEMAND);
+ onScanVolume(this, volume, reason);
break;
}
default: {
@@ -100,21 +120,30 @@
}
}
- private static void onScanVolume(Context context, Uri uri, int reason)
+ private static void onScanVolume(Context context, Intent intent, int reason)
throws IOException {
- final File file = new File(uri.getPath()).getCanonicalFile();
- final String volumeName = FileUtils.getVolumeName(context, file);
- onScanVolume(context, volumeName, reason);
+ final StorageVolume volume = intent.getParcelableExtra(StorageVolume.EXTRA_STORAGE_VOLUME);
+ if (volume != null) {
+ onScanVolume(context, MediaVolume.fromStorageVolume(volume), reason);
+ } else {
+ Log.e(TAG, "Couldn't retrieve StorageVolume from intent");
+ }
}
- public static void onScanVolume(Context context, String volumeName, int reason)
+ public static void onScanVolume(Context context, MediaVolume volume, int reason)
throws IOException {
+ final String volumeName = volume.getName();
+ UserHandle owner = volume.getUser();
+ if (owner == null) {
+ // Can happen for the internal volume
+ owner = context.getUser();
+ }
// If we're about to scan any external storage, scan internal first
// to ensure that we have ringtones ready to roll before a possibly very
// long external storage scan
if (!MediaStore.VOLUME_INTERNAL.equals(volumeName)) {
- onScanVolume(context, MediaStore.VOLUME_INTERNAL, reason);
+ onScanVolume(context, MediaVolume.fromInternal(), reason);
RingtoneManager.ensureDefaultRingtones(context);
}
@@ -123,7 +152,7 @@
// in the situation where a volume is ejected mid-scan
final Uri broadcastUri;
if (!MediaStore.VOLUME_INTERNAL.equals(volumeName)) {
- broadcastUri = Uri.fromFile(FileUtils.getVolumePath(context, volumeName));
+ broadcastUri = Uri.fromFile(volume.getPath());
} else {
broadcastUri = null;
}
@@ -131,7 +160,7 @@
try (ContentProviderClient cpc = context.getContentResolver()
.acquireContentProviderClient(MediaStore.AUTHORITY)) {
final MediaProvider provider = ((MediaProvider) cpc.getLocalContentProvider());
- provider.attachVolume(volumeName, /* validate */ true);
+ provider.attachVolume(volume, /* validate */ true);
final ContentResolver resolver = ContentResolver.wrap(cpc.getLocalContentProvider());
@@ -140,20 +169,24 @@
Uri scanUri = resolver.insert(MediaStore.getMediaScannerUri(), values);
if (broadcastUri != null) {
- context.sendBroadcast(
- new Intent(Intent.ACTION_MEDIA_SCANNER_STARTED, broadcastUri));
+ context.sendBroadcastAsUser(
+ new Intent(Intent.ACTION_MEDIA_SCANNER_STARTED, broadcastUri), owner);
}
- for (File dir : FileUtils.getVolumeScanPaths(context, volumeName)) {
- provider.scanDirectory(dir, reason);
+ if (MediaStore.VOLUME_INTERNAL.equals(volumeName)) {
+ for (File dir : FileUtils.getVolumeScanPaths(context, volumeName)) {
+ provider.scanDirectory(dir, reason);
+ }
+ } else {
+ provider.scanDirectory(volume.getPath(), reason);
}
resolver.delete(scanUri, null, null);
} finally {
if (broadcastUri != null) {
- context.sendBroadcast(
- new Intent(Intent.ACTION_MEDIA_SCANNER_FINISHED, broadcastUri));
+ context.sendBroadcastAsUser(
+ new Intent(Intent.ACTION_MEDIA_SCANNER_FINISHED, broadcastUri), owner);
}
}
}
diff --git a/src/com/android/providers/media/MediaVolume.java b/src/com/android/providers/media/MediaVolume.java
new file mode 100644
index 0000000..461f67d
--- /dev/null
+++ b/src/com/android/providers/media/MediaVolume.java
@@ -0,0 +1,153 @@
+/*
+ * 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;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.UserHandle;
+import android.os.storage.StorageVolume;
+import android.provider.MediaStore;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.io.File;
+import java.util.Objects;
+
+/**
+ * MediaVolume is a MediaProvider-internal representation of a storage volume.
+ *
+ * Before MediaVolume, volumes inside MediaProvider were represented by their name;
+ * but now that MediaProvider handles volumes on behalf on multiple users, the name of a volume
+ * might no longer be unique. So MediaVolume holds both a name and a user. The user may be
+ * null on volumes without an owner (eg public volumes).
+ *
+ * In addition to that, we keep the path and ID of the volume cached in here as well
+ * for easy access.
+ */
+public final class MediaVolume implements Parcelable {
+ /**
+ * Name of the volume.
+ */
+ private final @NonNull String mName;
+
+ /**
+ * User to which the volume belongs to; might be null in case of public volumes.
+ */
+ private final @Nullable UserHandle mUser;
+
+ /**
+ * Path on which the volume is mounted.
+ */
+ private final @Nullable File mPath;
+
+ /**
+ * Unique ID of the volume; eg "external;0"
+ */
+ private final @Nullable String mId;
+
+ public @NonNull String getName() {
+ return mName;
+ }
+
+ public @Nullable UserHandle getUser() {
+ return mUser;
+ }
+
+ public @Nullable File getPath() {
+ return mPath;
+ }
+
+ public @Nullable String getId() {
+ return mId;
+ }
+
+ private MediaVolume (@NonNull String name, UserHandle user, File path, String id) {
+ this.mName = name;
+ this.mUser = user;
+ this.mPath = path;
+ this.mId = id;
+ }
+
+ private MediaVolume (Parcel in) {
+ this.mName = in.readString();
+ this.mUser = in.readParcelable(null);
+ this.mPath = new File(in.readString());
+ this.mId = in.readString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null || getClass() != obj.getClass()) return false;
+ MediaVolume that = (MediaVolume) obj;
+ return Objects.equals(mName, that.mName) &&
+ Objects.equals(mUser, that.mUser) &&
+ Objects.equals(mPath, that.mPath) &&
+ Objects.equals(mId, that.mId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mName, mUser, mPath, mId);
+ }
+
+ public boolean isVisibleToUser(UserHandle user) {
+ return mUser == null || user.equals(mUser);
+ }
+
+ @NonNull
+ public static MediaVolume fromStorageVolume(StorageVolume storageVolume) {
+ String name = storageVolume.getMediaStoreVolumeName();
+ UserHandle user = storageVolume.getOwner();
+ File path = storageVolume.getDirectory();
+ String id = storageVolume.getId();
+ return new MediaVolume(name, user, path, id);
+ }
+
+ public static MediaVolume fromInternal() {
+ String name = MediaStore.VOLUME_INTERNAL;
+
+ return new MediaVolume(name, null, null, null);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mName);
+ dest.writeParcelable(mUser, flags);
+ dest.writeString(mPath.toString());
+ dest.writeString(mId);
+ }
+
+ public static final @android.annotation.NonNull Creator<MediaVolume> CREATOR
+ = new Creator<MediaVolume>() {
+ @Override
+ public MediaVolume createFromParcel(Parcel in) {
+ return new MediaVolume(in);
+ }
+
+ @Override
+ public MediaVolume[] newArray(int size) {
+ return new MediaVolume[size];
+ }
+ };
+}
diff --git a/src/com/android/providers/media/PermissionActivity.java b/src/com/android/providers/media/PermissionActivity.java
index c088aec..ee37448 100644
--- a/src/com/android/providers/media/PermissionActivity.java
+++ b/src/com/android/providers/media/PermissionActivity.java
@@ -22,10 +22,14 @@
import static com.android.providers.media.MediaProvider.collectUris;
import static com.android.providers.media.util.DatabaseUtils.getAsBoolean;
import static com.android.providers.media.util.Logging.TAG;
+import static com.android.providers.media.util.PermissionUtils.checkPermissionAccessMediaLocation;
+import static com.android.providers.media.util.PermissionUtils.checkPermissionManageMedia;
+import static com.android.providers.media.util.PermissionUtils.checkPermissionManager;
+import static com.android.providers.media.util.PermissionUtils.checkPermissionReadStorage;
import android.app.Activity;
import android.app.AlertDialog;
-import android.app.ProgressDialog;
+import android.app.Dialog;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.ContentValues;
@@ -50,7 +54,6 @@
import android.provider.MediaStore;
import android.provider.MediaStore.MediaColumns;
import android.text.TextUtils;
-import android.text.format.DateUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Size;
@@ -60,10 +63,12 @@
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.widget.ImageView;
+import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import com.android.providers.media.MediaProvider.LocalUriMatcher;
import com.android.providers.media.util.Metrics;
@@ -103,16 +108,28 @@
private AlertDialog actionDialog;
private AsyncTask<Void, Void, Void> positiveActionTask;
- private ProgressDialog progressDialog;
+ private Dialog progressDialog;
private TextView titleView;
+ private Handler mHandler;
+ private Runnable mShowProgressDialogRunnable = () -> {
+ // We will show the progress dialog, add the dim effect back.
+ getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+ progressDialog.show();
+ };
private static final Long LEAST_SHOW_PROGRESS_TIME_MS = 300L;
+ private static final Long BEFORE_SHOW_PROGRESS_TIME_MS = 300L;
- private static final String VERB_WRITE = "write";
- private static final String VERB_TRASH = "trash";
+ @VisibleForTesting
+ static final String VERB_WRITE = "write";
+ @VisibleForTesting
+ static final String VERB_TRASH = "trash";
+ @VisibleForTesting
+ static final String VERB_FAVORITE = "favorite";
+ @VisibleForTesting
+ static final String VERB_UNFAVORITE = "unfavorite";
+
private static final String VERB_UNTRASH = "untrash";
- private static final String VERB_FAVORITE = "favorite";
- private static final String VERB_UNFAVORITE = "unfavorite";
private static final String VERB_DELETE = "delete";
private static final String DATA_AUDIO = "audio";
@@ -136,6 +153,12 @@
getWindow().addSystemFlags(
WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
setFinishOnTouchOutside(false);
+ // remove the dim effect
+ // We may not show the progress dialog, if we don't remove the dim effect,
+ // it may have flicker.
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+ getWindow().setDimAmount(0.0f);
+
// All untrusted input values here were validated when generating the
// original PendingIntent
@@ -154,31 +177,21 @@
return;
}
- progressDialog = new ProgressDialog(this);
- progressDialog.setCancelable(false);
+ mHandler = new Handler(getMainLooper());
+ // Create Progress dialog
+ createProgressDialog();
- // Favorite-related requests are automatically granted for now; we still
- // make developers go through this no-op dialog flow to preserve our
- // ability to start prompting in the future
- switch (verb) {
- case VERB_FAVORITE:
- case VERB_UNFAVORITE: {
- onPositiveAction(null, 0);
- return;
- }
+ if (!shouldShowActionDialog(this, -1 /* pid */, appInfo.uid, getCallingPackage(),
+ null /* attributionTag */, verb)) {
+ onPositiveAction(null, 0);
+ return;
}
+
// Kick off async loading of description to show in dialog
final View bodyView = getLayoutInflater().inflate(R.layout.permission_body, null, false);
handleImageViewVisibility(bodyView, uris);
new DescriptionTask(bodyView).execute(uris);
- final CharSequence message = resolveMessageText();
- if (!TextUtils.isEmpty(message)) {
- final TextView messageView = bodyView.requireViewById(R.id.message);
- messageView.setVisibility(View.VISIBLE);
- messageView.setText(message);
- }
-
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
// We set the title in message so that the text doesn't get truncated
builder.setMessage(resolveTitleText());
@@ -211,9 +224,23 @@
});
}
+ private void createProgressDialog() {
+ final ProgressBar progressBar = new ProgressBar(this);
+ final int padding = getResources().getDimensionPixelOffset(R.dimen.dialog_space);
+
+ progressBar.setIndeterminate(true);
+ progressBar.setPadding(0, padding / 2, 0, padding);
+ progressDialog = new AlertDialog.Builder(this)
+ .setTitle(resolveProgressMessageText())
+ .setView(progressBar)
+ .setCancelable(false)
+ .create();
+ }
+
@Override
public void onDestroy() {
super.onDestroy();
+ mHandler.removeCallbacks(mShowProgressDialogRunnable);
// Cancel and interrupt the AsyncTask of the positive action. This avoids
// calling the old activity during "onPostExecute", but the AsyncTask could
// still finish its background task. For now we are ok with:
@@ -239,8 +266,10 @@
((AlertDialog) dialog).getButton(AlertDialog.BUTTON_NEGATIVE).setEnabled(false);
}
- progressDialog.show();
final long startTime = System.currentTimeMillis();
+
+ mHandler.postDelayed(mShowProgressDialogRunnable, BEFORE_SHOW_PROGRESS_TIME_MS);
+
positiveActionTask = new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
@@ -291,17 +320,23 @@
@Override
protected void onPostExecute(Void result) {
setResult(Activity.RESULT_OK);
- // Don't dismiss the progress dialog too quick, it will cause bad UX.
- final long duration = System.currentTimeMillis() - startTime;
- if (duration > LEAST_SHOW_PROGRESS_TIME_MS) {
- progressDialog.dismiss();
+ mHandler.removeCallbacks(mShowProgressDialogRunnable);
+
+ if (!progressDialog.isShowing()) {
finish();
} else {
- Handler handler = new Handler(getMainLooper());
- handler.postDelayed(() -> {
+ // Don't dismiss the progress dialog too quick, it will cause bad UX.
+ final long duration =
+ System.currentTimeMillis() - startTime - BEFORE_SHOW_PROGRESS_TIME_MS;
+ if (duration > LEAST_SHOW_PROGRESS_TIME_MS) {
progressDialog.dismiss();
finish();
- }, LEAST_SHOW_PROGRESS_TIME_MS - duration);
+ } else {
+ mHandler.postDelayed(() -> {
+ progressDialog.dismiss();
+ finish();
+ }, LEAST_SHOW_PROGRESS_TIME_MS - duration);
+ }
}
}
}.execute();
@@ -337,6 +372,37 @@
return keyCode == KeyEvent.KEYCODE_BACK;
}
+ @VisibleForTesting
+ static boolean shouldShowActionDialog(@NonNull Context context, int pid, int uid,
+ @NonNull String packageName, @Nullable String attributionTag, @NonNull String verb) {
+ // Favorite-related requests are automatically granted for now; we still
+ // make developers go through this no-op dialog flow to preserve our
+ // ability to start prompting in the future
+ if (TextUtils.equals(VERB_FAVORITE, verb) || TextUtils.equals(VERB_UNFAVORITE, verb)) {
+ return false;
+ }
+
+ // check READ_EXTERNAL_STORAGE and MANAGE_EXTERNAL_STORAGE permissions
+ if (!checkPermissionReadStorage(context, pid, uid, packageName, attributionTag)
+ && !checkPermissionManager(context, pid, uid, packageName, attributionTag)) {
+ Log.d(TAG, "No permission READ_EXTERNAL_STORAGE or MANAGE_EXTERNAL_STORAGE");
+ return true;
+ }
+ // check MANAGE_MEDIA permission
+ if (!checkPermissionManageMedia(context, pid, uid, packageName, attributionTag)) {
+ Log.d(TAG, "No permission MANAGE_MEDIA");
+ return true;
+ }
+
+ // if verb is write, check ACCESS_MEDIA_LOCATION permission
+ if (TextUtils.equals(verb, VERB_WRITE) && !checkPermissionAccessMediaLocation(context, pid,
+ uid, packageName, attributionTag)) {
+ Log.d(TAG, "No permission ACCESS_MEDIA_LOCATION");
+ return true;
+ }
+ return false;
+ }
+
private void handleImageViewVisibility(View bodyView, List<Uri> uris) {
if (uris.isEmpty()) {
return;
@@ -451,43 +517,24 @@
}
/**
- * Resolve the dialog message string to be displayed to the user, if any.
- * All arguments have been bound and this string is ready to be displayed.
+ * Resolve the progress message string to be displayed to the user. All
+ * arguments have been bound and this string is ready to be displayed.
*/
- private @Nullable CharSequence resolveMessageText() {
- final String resName = "permission_" + verb + "_" + data + "_info";
+ private @Nullable CharSequence resolveProgressMessageText() {
+ final String resName = "permission_progress_" + verb + "_" + data;
final int resId = getResources().getIdentifier(resName, "plurals",
getResources().getResourcePackageName(R.string.app_label));
if (resId != 0) {
final int count = uris.size();
- final long durationMillis = (values.getAsLong(MediaColumns.DATE_EXPIRES) * 1000)
- - System.currentTimeMillis();
- final long durationDays = (durationMillis + DateUtils.DAY_IN_MILLIS)
- / DateUtils.DAY_IN_MILLIS;
final CharSequence text = getResources().getQuantityText(resId, count);
- return TextUtils.expandTemplate(text, label, String.valueOf(count),
- String.valueOf(durationDays));
+ return TextUtils.expandTemplate(text, String.valueOf(count));
} else {
- // Only some actions have a secondary message string; it's okay if
+ // Only some actions have a progress message string; it's okay if
// there isn't one defined
return null;
}
}
- private @NonNull CharSequence resolvePositiveText() {
- final String resName = "permission_" + verb + "_grant";
- final int resId = getResources().getIdentifier(resName, "string",
- getResources().getResourcePackageName(R.string.app_label));
- return getResources().getText(resId);
- }
-
- private @NonNull CharSequence resolveNegativeText() {
- final String resName = "permission_" + verb + "_deny";
- final int resId = getResources().getIdentifier(resName, "string",
- getResources().getResourcePackageName(R.string.app_label));
- return getResources().getText(resId);
- }
-
/**
* Recursively walk the given view hierarchy looking for the first
* {@link View} which matches the given predicate.
diff --git a/src/com/android/providers/media/TranscodeHelper.java b/src/com/android/providers/media/TranscodeHelper.java
new file mode 100644
index 0000000..c500bf6
--- /dev/null
+++ b/src/com/android/providers/media/TranscodeHelper.java
@@ -0,0 +1,1855 @@
+/*
+ * Copyright (C) 2020 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.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
+import static android.provider.MediaStore.Files.FileColumns.TRANSCODE_COMPLETE;
+import static android.provider.MediaStore.Files.FileColumns.TRANSCODE_EMPTY;
+import static android.provider.MediaStore.MATCH_EXCLUDE;
+import static android.provider.MediaStore.QUERY_ARG_MATCH_PENDING;
+import static android.provider.MediaStore.QUERY_ARG_MATCH_TRASHED;
+
+import static com.android.providers.media.MediaProvider.VolumeNotFoundException;
+import static com.android.providers.media.MediaProviderStatsLog.TRANSCODING_DATA;
+import static com.android.providers.media.MediaProviderStatsLog.TRANSCODING_DATA__FAILURE_CAUSE__CAUSE_UNKNOWN;
+import static com.android.providers.media.MediaProviderStatsLog.TRANSCODING_DATA__FAILURE_CAUSE__TRANSCODING_CLIENT_TIMEOUT;
+import static com.android.providers.media.MediaProviderStatsLog.TRANSCODING_DATA__FAILURE_CAUSE__TRANSCODING_SERVICE_ERROR;
+import static com.android.providers.media.MediaProviderStatsLog.TRANSCODING_DATA__FAILURE_CAUSE__TRANSCODING_SESSION_CANCELED;
+import static com.android.providers.media.MediaProviderStatsLog.TRANSCODING_DATA__TRANSCODE_RESULT__FAIL;
+import static com.android.providers.media.MediaProviderStatsLog.TRANSCODING_DATA__TRANSCODE_RESULT__SUCCESS;
+import static com.android.providers.media.MediaProviderStatsLog.TRANSCODING_DATA__TRANSCODE_RESULT__UNDEFINED;
+
+import android.annotation.IntRange;
+import android.annotation.LongDef;
+import android.app.ActivityManager;
+import android.app.ActivityManager.OnUidImportanceListener;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.Disabled;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.InstallSourceInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.Property;
+import android.content.res.XmlResourceParser;
+import android.database.Cursor;
+import android.media.ApplicationMediaCapabilities;
+import android.media.MediaFeature;
+import android.media.MediaFormat;
+import android.media.MediaTranscodeManager;
+import android.media.MediaTranscodeManager.VideoTranscodingRequest;
+import android.media.MediaTranscodeManager.TranscodingRequest.VideoFormatResolver;
+import android.media.MediaTranscodeManager.TranscodingSession;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageVolume;
+import android.provider.MediaStore;
+import android.provider.MediaStore.Files.FileColumns;
+import android.provider.MediaStore.MediaColumns;
+import android.provider.MediaStore.Video.VideoColumns;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Pair;
+import android.util.SparseArray;
+import android.widget.Toast;
+
+import androidx.annotation.GuardedBy;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.app.NotificationCompat;
+import androidx.core.app.NotificationManagerCompat;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.modules.utils.build.SdkLevel;
+import com.android.providers.media.util.BackgroundThread;
+import com.android.providers.media.util.FileUtils;
+import com.android.providers.media.util.ForegroundThread;
+import com.android.providers.media.util.SQLiteQueryBuilder;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.RandomAccessFile;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
+import java.util.LinkedHashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class TranscodeHelper {
+ private static final String TAG = "TranscodeHelper";
+ private static final boolean DEBUG = SystemProperties.getBoolean("persist.sys.fuse.log", false);
+ private static final float MAX_APP_NAME_SIZE_PX = 500f;
+
+ // Notice the pairing of the keys.When you change a DEVICE_CONFIG key, then please also change
+ // the corresponding SYS_PROP key too; and vice-versa.
+ // Keeping the whole strings separate for the ease of text search.
+ private static final String TRANSCODE_ENABLED_SYS_PROP_KEY =
+ "persist.sys.fuse.transcode_enabled";
+ private static final String TRANSCODE_ENABLED_DEVICE_CONFIG_KEY = "transcode_enabled";
+ private static final String TRANSCODE_DEFAULT_SYS_PROP_KEY =
+ "persist.sys.fuse.transcode_default";
+ private static final String TRANSCODE_DEFAULT_DEVICE_CONFIG_KEY = "transcode_default";
+ private static final String TRANSCODE_USER_CONTROL_SYS_PROP_KEY =
+ "persist.sys.fuse.transcode_user_control";
+ private static final String TRANSCODE_COMPAT_MANIFEST_KEY = "transcode_compat_manifest";
+ private static final String TRANSCODE_COMPAT_STALE_KEY = "transcode_compat_stale";
+ private static final String TRANSCODE_MAX_DURATION_MS_KEY = "transcode_max_duration_ms";
+
+ private static final int MY_UID = android.os.Process.myUid();
+ private static final int MAX_TRANSCODE_DURATION_MS = (int) TimeUnit.MINUTES.toMillis(1);
+
+ /**
+ * Force enable an app to support the HEVC media capability
+ *
+ * Apps should declare their supported media capabilities in their manifest but this flag can be
+ * used to force an app into supporting HEVC, hence avoiding transcoding while accessing media
+ * encoded in HEVC.
+ *
+ * Setting this flag will override any OS level defaults for apps. It is disabled by default,
+ * meaning that the OS defaults would take precedence.
+ *
+ * Setting this flag and {@code FORCE_DISABLE_HEVC_SUPPORT} is an undefined
+ * state and will result in the OS ignoring both flags.
+ */
+ @ChangeId
+ @Disabled
+ private static final long FORCE_ENABLE_HEVC_SUPPORT = 174228127L;
+
+ /**
+ * Force disable an app from supporting the HEVC media capability
+ *
+ * Apps should declare their supported media capabilities in their manifest but this flag can be
+ * used to force an app into not supporting HEVC, hence forcing transcoding while accessing
+ * media encoded in HEVC.
+ *
+ * Setting this flag will override any OS level defaults for apps. It is disabled by default,
+ * meaning that the OS defaults would take precedence.
+ *
+ * Setting this flag and {@code FORCE_ENABLE_HEVC_SUPPORT} is an undefined state
+ * and will result in the OS ignoring both flags.
+ */
+ @ChangeId
+ @Disabled
+ private static final long FORCE_DISABLE_HEVC_SUPPORT = 174227820L;
+
+ @VisibleForTesting
+ static final int FLAG_HEVC = 1 << 0;
+ @VisibleForTesting
+ static final int FLAG_SLOW_MOTION = 1 << 1;
+ private static final int FLAG_HDR_10 = 1 << 2;
+ private static final int FLAG_HDR_10_PLUS = 1 << 3;
+ private static final int FLAG_HDR_HLG = 1 << 4;
+ private static final int FLAG_HDR_DOLBY_VISION = 1 << 5;
+ private static final int MEDIA_FORMAT_FLAG_MASK = FLAG_HEVC | FLAG_SLOW_MOTION
+ | FLAG_HDR_10 | FLAG_HDR_10_PLUS | FLAG_HDR_HLG | FLAG_HDR_DOLBY_VISION;
+
+ @LongDef({
+ FLAG_HEVC,
+ FLAG_SLOW_MOTION,
+ FLAG_HDR_10,
+ FLAG_HDR_10_PLUS,
+ FLAG_HDR_HLG,
+ FLAG_HDR_DOLBY_VISION
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ApplicationMediaCapabilitiesFlags {
+ }
+
+ /** Coefficient to 'guess' how long a transcoding session might take */
+ private static final double TRANSCODING_TIMEOUT_COEFFICIENT = 2;
+ /** Coefficient to 'guess' how large a transcoded file might be */
+ private static final double TRANSCODING_SIZE_COEFFICIENT = 2;
+
+ /**
+ * Copied from MediaProvider.java
+ * TODO(b/170465810): Remove this when getQueryBuilder code is refactored.
+ */
+ private static final int TYPE_QUERY = 0;
+ private static final int TYPE_UPDATE = 2;
+
+ private static final int MAX_FINISHED_TRANSCODING_SESSION_STORE_COUNT = 16;
+ private static final String DIRECTORY_CAMERA = "Camera";
+
+ private static final boolean IS_TRANSCODING_SUPPORTED = SdkLevel.isAtLeastS();
+
+ private final Object mLock = new Object();
+ private final Context mContext;
+ private final MediaProvider mMediaProvider;
+ private final PackageManager mPackageManager;
+ private final StorageManager mStorageManager;
+ private final ActivityManager mActivityManager;
+ private final File mTranscodeDirectory;
+ @GuardedBy("mLock")
+ private UUID mTranscodeVolumeUuid;
+
+ @GuardedBy("mLock")
+ private final Map<String, StorageTranscodingSession> mStorageTranscodingSessions =
+ new ArrayMap<>();
+
+ // These are for dumping purpose only.
+ // We keep these separately because the probability of getting cancelled and error'ed sessions
+ // is pretty low, and we are limiting the count of what we keep. So, we don't wanna miss out
+ // on dumping the cancelled and error'ed sessions.
+ @GuardedBy("mLock")
+ private final Map<StorageTranscodingSession, Boolean> mSuccessfulTranscodeSessions =
+ createFinishedTranscodingSessionMap();
+ @GuardedBy("mLock")
+ private final Map<StorageTranscodingSession, Boolean> mCancelledTranscodeSessions =
+ createFinishedTranscodingSessionMap();
+ @GuardedBy("mLock")
+ private final Map<StorageTranscodingSession, Boolean> mErroredTranscodeSessions =
+ createFinishedTranscodingSessionMap();
+
+ private final TranscodeUiNotifier mTranscodingUiNotifier;
+ private final TranscodeDenialController mTranscodeDenialController;
+ private final SessionTiming mSessionTiming;
+ @GuardedBy("mLock")
+ private final Map<String, Integer> mAppCompatMediaCapabilities = new ArrayMap<>();
+ @GuardedBy("mLock")
+ private boolean mIsTranscodeEnabled;
+
+ private static final String[] TRANSCODE_CACHE_INFO_PROJECTION =
+ {FileColumns._ID, FileColumns._TRANSCODE_STATUS};
+ private static final String TRANSCODE_WHERE_CLAUSE =
+ FileColumns.DATA + "=?" + " and mime_type not like 'null'";
+
+ public TranscodeHelper(Context context, MediaProvider mediaProvider) {
+ mContext = context;
+ mPackageManager = context.getPackageManager();
+ mStorageManager = context.getSystemService(StorageManager.class);
+ mActivityManager = context.getSystemService(ActivityManager.class);
+ mMediaProvider = mediaProvider;
+ mTranscodeDirectory = new File("/storage/emulated/" + UserHandle.myUserId(),
+ DIRECTORY_TRANSCODE);
+ mTranscodeDirectory.mkdirs();
+ mSessionTiming = new SessionTiming();
+ mTranscodingUiNotifier = new TranscodeUiNotifier(context, mSessionTiming);
+ mIsTranscodeEnabled = isTranscodeEnabled();
+ int maxTranscodeDurationMs =
+ mMediaProvider.getIntDeviceConfig(TRANSCODE_MAX_DURATION_MS_KEY,
+ MAX_TRANSCODE_DURATION_MS);
+ mTranscodeDenialController = new TranscodeDenialController(mActivityManager,
+ mTranscodingUiNotifier, maxTranscodeDurationMs);
+
+ parseTranscodeCompatManifest();
+ // The storage namespace is a boot namespace so we actually don't expect this to be changed
+ // after boot, but it is useful for tests
+ mMediaProvider.addOnPropertiesChangedListener(properties -> parseTranscodeCompatManifest());
+ }
+
+ /**
+ * Regex that matches path of transcode file. The regex only
+ * matches emulated volume, for files in other volumes we don't
+ * seamlessly transcode.
+ */
+ private static final Pattern PATTERN_TRANSCODE_PATH = Pattern.compile(
+ "(?i)^/storage/emulated/(?:[0-9]+)/\\.transforms/transcode/(?:\\d+)$");
+ private static final String DIRECTORY_TRANSCODE = ".transforms/transcode";
+ /**
+ * @return true if the file path matches transcode file path.
+ */
+ private static boolean isTranscodeFile(@NonNull String path) {
+ final Matcher matcher = PATTERN_TRANSCODE_PATH.matcher(path);
+ return matcher.matches();
+ }
+
+ public void freeCache(long bytes) {
+ File[] files = mTranscodeDirectory.listFiles();
+ for (File file : files) {
+ if (bytes <= 0) {
+ return;
+ }
+ if (file.exists() && file.isFile()) {
+ long size = file.length();
+ boolean deleted = file.delete();
+ if (deleted) {
+ bytes -= size;
+ }
+ }
+ }
+ }
+
+ private UUID getTranscodeVolumeUuid() {
+ synchronized (mLock) {
+ if (mTranscodeVolumeUuid != null) {
+ return mTranscodeVolumeUuid;
+ }
+ }
+
+ StorageVolume vol = mStorageManager.getStorageVolume(mTranscodeDirectory);
+ if (vol != null) {
+ synchronized (mLock) {
+ mTranscodeVolumeUuid = vol.getStorageUuid();
+ return mTranscodeVolumeUuid;
+ }
+ } else {
+ Log.w(TAG, "Failed to get storage volume UUID for: " + mTranscodeDirectory);
+ return null;
+ }
+ }
+
+ /**
+ * @return transcode file's path for given {@code rowId}
+ */
+ @NonNull
+ private String getTranscodePath(long rowId) {
+ return new File(mTranscodeDirectory, String.valueOf(rowId)).getAbsolutePath();
+ }
+
+ public void onAnrDelayStarted(String packageName, int uid, int tid, int reason) {
+ if (!isTranscodeEnabled()) {
+ return;
+ }
+
+ if (uid == MY_UID) {
+ Log.w(TAG, "Skipping ANR delay handling for MediaProvider");
+ return;
+ }
+
+ logVerbose("Checking transcode status during ANR of " + packageName);
+
+ Set<StorageTranscodingSession> sessions = new ArraySet<>();
+ synchronized (mLock) {
+ sessions.addAll(mStorageTranscodingSessions.values());
+ }
+
+ for (StorageTranscodingSession session: sessions) {
+ if (session.isUidBlocked(uid)) {
+ session.setAnr();
+ Log.i(TAG, "Package: " + packageName + " with uid: " + uid
+ + " and tid: " + tid + " is blocked on transcoding: " + session);
+ // TODO(b/170973510): Show UI
+ }
+ }
+ }
+
+ // TODO(b/170974147): This should probably use a cache so we don't need to ask the
+ // package manager every time for the package name or installer name
+ private String getMetricsSafeNameForUid(int uid) {
+ String name = mPackageManager.getNameForUid(uid);
+ if (name == null) {
+ Log.w(TAG, "null package name received from getNameForUid for uid " + uid
+ + ", logging uid instead.");
+ return Integer.toString(uid);
+ } else if (name.isEmpty()) {
+ Log.w(TAG, "empty package name received from getNameForUid for uid " + uid
+ + ", logging uid instead");
+ return ":empty_package_name:" + uid;
+ } else {
+ try {
+ InstallSourceInfo installInfo = mPackageManager.getInstallSourceInfo(name);
+ ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(name, 0);
+ if (installInfo.getInstallingPackageName() == null
+ && ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0)) {
+ // For privacy reasons, we don't log metrics for side-loaded packages that
+ // are not system packages
+ return ":installer_adb:" + uid;
+ }
+ return name;
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Unable to check installer for uid: " + uid, e);
+ return ":name_not_found:" + uid;
+ }
+ }
+ }
+
+ private void reportTranscodingResult(int uid, boolean success, int errorCode, int failureReason,
+ long transcodingDurationMs,
+ int transcodingReason, String src, String dst, boolean hasAnr) {
+ BackgroundThread.getExecutor().execute(() -> {
+ try (Cursor c = queryFileForTranscode(src,
+ new String[]{MediaColumns.DURATION, MediaColumns.CAPTURE_FRAMERATE,
+ MediaColumns.WIDTH, MediaColumns.HEIGHT})) {
+ if (c != null && c.moveToNext()) {
+ MediaProviderStatsLog.write(
+ TRANSCODING_DATA,
+ getMetricsSafeNameForUid(uid),
+ MediaProviderStatsLog.TRANSCODING_DATA__ACCESS_TYPE__READ_TRANSCODE,
+ success ? new File(dst).length() : -1,
+ success ? TRANSCODING_DATA__TRANSCODE_RESULT__SUCCESS :
+ TRANSCODING_DATA__TRANSCODE_RESULT__FAIL,
+ transcodingDurationMs,
+ c.getLong(0) /* video_duration */,
+ c.getLong(1) /* capture_framerate */,
+ transcodingReason,
+ c.getLong(2) /* width */,
+ c.getLong(3) /* height */,
+ hasAnr,
+ failureReason,
+ errorCode);
+ }
+ }
+ });
+ }
+
+ public boolean transcode(String src, String dst, int uid, int reason) {
+ // This can only happen when we are in a version that supports transcoding.
+ // So, no need to check for the SDK version here.
+
+ StorageTranscodingSession storageSession = null;
+ TranscodingSession transcodingSession = null;
+ CountDownLatch latch = null;
+ long startTime = SystemClock.elapsedRealtime();
+ boolean result = false;
+ int errorCode = TranscodingSession.ERROR_SERVICE_DIED;
+ int failureReason = TRANSCODING_DATA__FAILURE_CAUSE__TRANSCODING_SERVICE_ERROR;
+
+ try {
+ synchronized (mLock) {
+ storageSession = mStorageTranscodingSessions.get(src);
+ if (storageSession == null) {
+ latch = new CountDownLatch(1);
+ try {
+ transcodingSession = enqueueTranscodingSession(src, dst, uid, latch);
+ if (transcodingSession == null) {
+ Log.e(TAG, "Failed to enqueue request due to Service unavailable");
+ throw new IllegalStateException("Failed to enqueue request");
+ }
+ } catch (UnsupportedOperationException | IOException e) {
+ throw new IllegalStateException(e);
+ }
+ storageSession = new StorageTranscodingSession(transcodingSession, latch,
+ src, dst);
+ mStorageTranscodingSessions.put(src, storageSession);
+ } else {
+ latch = storageSession.latch;
+ transcodingSession = storageSession.session;
+ if (latch == null || transcodingSession == null) {
+ throw new IllegalStateException("Uninitialised TranscodingSession for uid: "
+ + uid + ". Path: " + src);
+ }
+ }
+ storageSession.addBlockedUid(uid);
+ }
+
+ failureReason = waitTranscodingResult(uid, src, transcodingSession, latch);
+ errorCode = transcodingSession.getErrorCode();
+ result = failureReason == TRANSCODING_DATA__FAILURE_CAUSE__CAUSE_UNKNOWN;
+
+ if (result) {
+ updateTranscodeStatus(src, TRANSCODE_COMPLETE);
+ } else {
+ logEvent("Transcoding failed for " + src + ". session: ", transcodingSession);
+ // Attempt to workaround potential media transcoding deadlock
+ // Cancelling a deadlocked session seems to unblock the transcoder
+ transcodingSession.cancel();
+ }
+ } finally {
+ if (storageSession == null) {
+ Log.w(TAG, "Failed to create a StorageTranscodingSession");
+ // We were unable to even queue the request. Which means the media service is
+ // in a very bad state
+ reportTranscodingResult(uid, result, errorCode, failureReason,
+ SystemClock.elapsedRealtime() - startTime, reason,
+ src, dst, false /* hasAnr */);
+ return false;
+ }
+
+ storageSession.notifyFinished(failureReason, errorCode);
+ if (errorCode == TranscodingSession.ERROR_DROPPED_BY_SERVICE) {
+ // If the transcoding service drops a request for a uid the uid will be denied
+ // transcoding access until the next boot, notify the denial controller which may
+ // also show a denial UI
+ mTranscodeDenialController.onTranscodingDropped(uid);
+ }
+ reportTranscodingResult(uid, result, errorCode, failureReason,
+ SystemClock.elapsedRealtime() - startTime, reason,
+ src, dst, storageSession.hasAnr());
+ }
+ return result;
+ }
+
+ /**
+ * Returns IO path for a {@code path} and {@code uid}
+ *
+ * IO path is the actual path to be used on the lower fs for IO via FUSE. For some file
+ * transforms, this path might be different from the path the app is requesting IO on.
+ *
+ * @param path file path to get an IO path for
+ * @param uid app requesting IO
+ *
+ */
+ public String getIoPath(String path, int uid) {
+ // This can only happen when we are in a version that supports transcoding.
+ // So, no need to check for the SDK version here.
+
+ Pair<Long, Integer> cacheInfo = getTranscodeCacheInfoFromDB(path);
+ final long rowId = cacheInfo.first;
+ if (rowId == -1) {
+ // No database row found, The file is pending/trashed or not added to database yet.
+ // Assuming that no transcoding needed.
+ return path;
+ }
+
+ int transcodeStatus = cacheInfo.second;
+ final String transcodePath = getTranscodePath(rowId);
+ final File transcodeFile = new File(transcodePath);
+
+ if (transcodeFile.exists()) {
+ return transcodePath;
+ }
+
+ if (transcodeStatus == TRANSCODE_COMPLETE) {
+ // The transcode file doesn't exist but db row is marked as TRANSCODE_COMPLETE,
+ // update db row to TRANSCODE_EMPTY so that cache state remains valid.
+ updateTranscodeStatus(path, TRANSCODE_EMPTY);
+ }
+
+ final File file = new File(path);
+ long maxFileSize = (long) (file.length() * 2);
+ mTranscodeDirectory.mkdirs();
+ try (RandomAccessFile raf = new RandomAccessFile(transcodeFile, "rw")) {
+ raf.setLength(maxFileSize);
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to initialise transcoding for file " + path, e);
+ transcodeFile.delete();
+ return transcodePath;
+ }
+
+ return transcodePath;
+ }
+
+ private static int getMediaCapabilitiesUid(int uid, Bundle bundle) {
+ if (bundle == null || !bundle.containsKey(MediaStore.EXTRA_MEDIA_CAPABILITIES_UID)) {
+ return uid;
+ }
+
+ int mediaCapabilitiesUid = bundle.getInt(MediaStore.EXTRA_MEDIA_CAPABILITIES_UID);
+ if (mediaCapabilitiesUid >= Process.FIRST_APPLICATION_UID) {
+ logVerbose(
+ "Media capabilities uid " + mediaCapabilitiesUid + ", passed for uid " + uid);
+ return mediaCapabilitiesUid;
+ }
+ Log.w(TAG, "Ignoring invalid media capabilities uid " + mediaCapabilitiesUid
+ + " for uid: " + uid);
+ return uid;
+ }
+
+ // TODO(b/173491972): Generalize to consider other file/app media capabilities beyond hevc
+ /**
+ * @return 0 or >0 representing whether we should transcode or not.
+ * 0 means we should not transcode, otherwise we should transcode and the value is the
+ * reason that will be logged to westworld as a transcode reason. Possible values are:
+ * <ul>
+ * <li>MediaProviderStatsLog.TRANSCODING_DATA__ACCESS_REASON__SYSTEM_DEFAULT=1
+ * <li>MediaProviderStatsLog.TRANSCODING_DATA__ACCESS_REASON__SYSTEM_CONFIG=2
+ * <li>MediaProviderStatsLog.TRANSCODING_DATA__ACCESS_REASON__APP_MANIFEST=3
+ * <li>MediaProviderStatsLog.TRANSCODING_DATA__ACCESS_REASON__APP_COMPAT=4
+ * <li>MediaProviderStatsLog.TRANSCODING_DATA__ACCESS_REASON__APP_EXTRA=5
+ * </ul>
+ *
+ */
+ public int shouldTranscode(String path, int uid, Bundle bundle) {
+ boolean isTranscodeEnabled = isTranscodeEnabled();
+ updateConfigs(isTranscodeEnabled);
+
+ if (!isTranscodeEnabled) {
+ logVerbose("Transcode not enabled");
+ return 0;
+ }
+
+ uid = getMediaCapabilitiesUid(uid, bundle);
+ logVerbose("Checking shouldTranscode for: " + path + ". Uid: " + uid);
+
+ if (!supportsTranscode(path) || uid < Process.FIRST_APPLICATION_UID || uid == MY_UID) {
+ logVerbose("Transcode not supported");
+ // Never transcode in any of these conditions
+ // 1. Path doesn't support transcode
+ // 2. Uid is from native process on device
+ // 3. Uid is ourselves, which can happen when we are opening a file via FUSE for
+ // redaction on behalf of another app via ContentResolver
+ return 0;
+ }
+
+ // Transcode only if file needs transcoding
+ Pair<Integer, Long> result = getFileFlagsAndDurationMs(path);
+ int fileFlags = result.first;
+ long durationMs = result.second;
+
+ if (fileFlags == 0) {
+ // Nothing to transcode
+ logVerbose("File is not HEVC");
+ return 0;
+ }
+
+ int accessReason = doesAppNeedTranscoding(uid, bundle, fileFlags, durationMs);
+ if (accessReason != 0 && mTranscodeDenialController.checkFileAccess(uid, durationMs)) {
+ logVerbose("Transcoding denied");
+ return 0;
+ }
+ return accessReason;
+ }
+
+ @VisibleForTesting
+ int doesAppNeedTranscoding(int uid, Bundle bundle, int fileFlags, long durationMs) {
+ // Check explicit Bundle provided
+ if (bundle != null) {
+ if (bundle.getBoolean(MediaStore.EXTRA_ACCEPT_ORIGINAL_MEDIA_FORMAT, false)) {
+ logVerbose("Original format requested");
+ return 0;
+ }
+
+ ApplicationMediaCapabilities capabilities =
+ bundle.getParcelable(MediaStore.EXTRA_MEDIA_CAPABILITIES);
+ if (capabilities != null) {
+ Pair<Integer, Integer> flags = capabilitiesToMediaFormatFlags(capabilities);
+ Optional<Boolean> appExtraResult = checkAppMediaSupport(flags.first, flags.second,
+ fileFlags, "app_extra");
+ if (appExtraResult.isPresent()) {
+ if (appExtraResult.get()) {
+ return MediaProviderStatsLog.TRANSCODING_DATA__ACCESS_REASON__APP_EXTRA;
+ }
+ return 0;
+ }
+ // Bundle didn't have enough information to make decision, continue
+ }
+ }
+
+ // Check app compat support
+ Optional<Boolean> appCompatResult = checkAppCompatSupport(uid, fileFlags);
+ if (appCompatResult.isPresent()) {
+ if (appCompatResult.get()) {
+ return MediaProviderStatsLog.TRANSCODING_DATA__ACCESS_REASON__APP_COMPAT;
+ }
+ return 0;
+ }
+ // App compat didn't have enough information to make decision, continue
+
+ // If we are here then the file supports HEVC, so we only check if the package is in the
+ // mAppCompatCapabilities. If it's there, we will respect that value.
+ LocalCallingIdentity identity = mMediaProvider.getCachedCallingIdentityForTranscoding(uid);
+ final String[] callingPackages = identity.getSharedPackageNames();
+
+ // Check app manifest support
+ for (String callingPackage : callingPackages) {
+ Optional<Boolean> appManifestResult = checkManifestSupport(callingPackage, identity,
+ fileFlags);
+ if (appManifestResult.isPresent()) {
+ if (appManifestResult.get()) {
+ return MediaProviderStatsLog.TRANSCODING_DATA__ACCESS_REASON__APP_MANIFEST;
+ }
+ return 0;
+ }
+ // App manifest didn't have enough information to make decision, continue
+
+ // TODO(b/169327180): We should also check app's targetSDK version to verify if app
+ // still qualifies to be on these lists.
+ // Check config compat manifest
+ synchronized (mLock) {
+ if (mAppCompatMediaCapabilities.containsKey(callingPackage)) {
+ int configCompatFlags = mAppCompatMediaCapabilities.get(callingPackage);
+ int supportedFlags = configCompatFlags;
+ int unsupportedFlags = ~configCompatFlags & MEDIA_FORMAT_FLAG_MASK;
+
+ Optional<Boolean> systemConfigResult = checkAppMediaSupport(supportedFlags,
+ unsupportedFlags, fileFlags, "system_config");
+ if (systemConfigResult.isPresent()) {
+ if (systemConfigResult.get()) {
+ return MediaProviderStatsLog.TRANSCODING_DATA__ACCESS_REASON__SYSTEM_CONFIG;
+ }
+ return 0;
+ }
+ // Should never get here because the supported & unsupported flags should span
+ // the entire universe of file flags
+ }
+ }
+ }
+
+ // TODO: Need to add transcode_default as flags
+ if (shouldTranscodeDefault()) {
+ logVerbose("Default behavior should transcode");
+ return MediaProviderStatsLog.TRANSCODING_DATA__ACCESS_REASON__SYSTEM_DEFAULT;
+ } else {
+ logVerbose("Default behavior should not transcode");
+ return 0;
+ }
+ }
+
+ /**
+ * Checks if transcode is required for the given app media capabilities and file media formats
+ *
+ * @param appSupportedMediaFormatFlags bit mask of media capabilites explicitly supported by an
+ * app, e.g 001 indicating HEVC support
+ * @param appUnsupportedMediaFormatFlags bit mask of media capabilites explicitly not supported
+ * by an app, e.g 10 indicating HDR_10 is not supportted
+ * @param fileMediaFormatFlags bit mask of media capabilites contained in a file e.g 101
+ * indicating HEVC and HDR_10 media file
+ *
+ * @return {@code Optional} containing {@code boolean}. {@code true} means transcode is
+ * required, {@code false} means transcode is not required and {@code empty} means a decision
+ * could not be made.
+ */
+ private Optional<Boolean> checkAppMediaSupport(int appSupportedMediaFormatFlags,
+ int appUnsupportedMediaFormatFlags, int fileMediaFormatFlags, String type) {
+ if ((appSupportedMediaFormatFlags & appUnsupportedMediaFormatFlags) != 0) {
+ Log.w(TAG, "Ignoring app media capabilities for type: [" + type
+ + "]. Supported and unsupported capapbilities are not mutually exclusive");
+ return Optional.empty();
+ }
+
+ // As an example:
+ // 1. appSupportedMediaFormatFlags=001 # App supports HEVC
+ // 2. appUnsupportedMediaFormatFlags=100 # App does not support HDR_10
+ // 3. fileSupportedMediaFormatFlags=101 # File contains HEVC and HDR_10
+
+ // File contains HDR_10 but app explicitly doesn't support it
+ int fileMediaFormatsUnsupportedByApp =
+ fileMediaFormatFlags & appUnsupportedMediaFormatFlags;
+ if (fileMediaFormatsUnsupportedByApp != 0) {
+ // If *any* file media formats are unsupported by the app we need to transcode
+ logVerbose("App media capability check for type: [" + type + "]" + ". transcode=true");
+ return Optional.of(true);
+ }
+
+ // fileMediaFormatsSupportedByApp=001 # File contains HEVC but app explicitly supports HEVC
+ int fileMediaFormatsSupportedByApp = appSupportedMediaFormatFlags & fileMediaFormatFlags;
+ // fileMediaFormatsNotSupportedByApp=100 # File contains HDR_10 but app doesn't support it
+ int fileMediaFormatsNotSupportedByApp =
+ fileMediaFormatsSupportedByApp ^ fileMediaFormatFlags;
+ if (fileMediaFormatsNotSupportedByApp == 0) {
+ logVerbose("App media capability check for type: [" + type + "]" + ". transcode=false");
+ // If *all* file media formats are supported by the app, we don't need to transcode
+ return Optional.of(false);
+ }
+
+ // If there are some file media formats that are neither supported nor unsupported by the
+ // app we can't make a decision yet
+ return Optional.empty();
+ }
+
+ private Pair<Integer, Long> getFileFlagsAndDurationMs(String path) {
+ final String[] projection = new String[] {
+ FileColumns._VIDEO_CODEC_TYPE,
+ VideoColumns.COLOR_STANDARD,
+ VideoColumns.COLOR_TRANSFER,
+ MediaColumns.DURATION
+ };
+
+ try (Cursor cursor = queryFileForTranscode(path, projection)) {
+ if (cursor == null || !cursor.moveToNext()) {
+ logVerbose("Couldn't find database row");
+ return Pair.create(0, 0L);
+ }
+
+ int result = 0;
+ if (isHevc(cursor.getString(0))) {
+ result |= FLAG_HEVC;
+ }
+ if (isHdr10Plus(cursor.getInt(1), cursor.getInt(2))) {
+ result |= FLAG_HDR_10_PLUS;
+ }
+ return Pair.create(result, cursor.getLong(3));
+ }
+ }
+
+ private static boolean isHevc(String mimeType) {
+ return MediaFormat.MIMETYPE_VIDEO_HEVC.equalsIgnoreCase(mimeType);
+ }
+
+ private static boolean isHdr10Plus(int colorStandard, int colorTransfer) {
+ return (colorStandard == MediaFormat.COLOR_STANDARD_BT2020) &&
+ (colorTransfer == MediaFormat.COLOR_TRANSFER_ST2084
+ || colorTransfer == MediaFormat.COLOR_TRANSFER_HLG);
+ }
+
+ private static boolean isModernFormat(String mimeType, int colorStandard, int colorTransfer) {
+ return isHevc(mimeType) || isHdr10Plus(colorStandard, colorTransfer);
+ }
+
+ public static boolean supportsTranscode(String path) {
+ File file = new File(path);
+ String name = file.getName();
+ final String cameraRelativePath =
+ String.format("%s/%s/", Environment.DIRECTORY_DCIM, DIRECTORY_CAMERA);
+
+ return !isTranscodeFile(path) && name.toLowerCase(Locale.ROOT).endsWith(".mp4")
+ && path.startsWith("/storage/emulated/")
+ && cameraRelativePath.equalsIgnoreCase(FileUtils.extractRelativePath(path));
+ }
+
+ private Optional<Boolean> checkAppCompatSupport(int uid, int fileFlags) {
+ int supportedFlags = 0;
+ int unsupportedFlags = 0;
+ boolean hevcSupportEnabled = CompatChanges.isChangeEnabled(FORCE_ENABLE_HEVC_SUPPORT, uid);
+ boolean hevcSupportDisabled = CompatChanges.isChangeEnabled(FORCE_DISABLE_HEVC_SUPPORT,
+ uid);
+ if (hevcSupportEnabled) {
+ supportedFlags = FLAG_HEVC;
+ logVerbose("App compat hevc support enabled");
+ }
+
+ if (hevcSupportDisabled) {
+ unsupportedFlags = FLAG_HEVC;
+ logVerbose("App compat hevc support disabled");
+ }
+ return checkAppMediaSupport(supportedFlags, unsupportedFlags, fileFlags, "app_compat");
+ }
+
+ /**
+ * @return {@code true} if HEVC is explicitly supported by the manifest of {@code packageName},
+ * {@code false} otherwise.
+ */
+ private Optional<Boolean> checkManifestSupport(String packageName,
+ LocalCallingIdentity identity, int fileFlags) {
+ // TODO(b/169327180):
+ // 1. Support beyond HEVC
+ // 2. Shared package names policy:
+ // If appA and appB share the same uid. And appA supports HEVC but appB doesn't.
+ // Should we assume entire uid supports or doesn't?
+ // For now, we assume uid supports, but this might change in future
+ int supportedFlags = identity.getApplicationMediaCapabilitiesSupportedFlags();
+ int unsupportedFlags = identity.getApplicationMediaCapabilitiesUnsupportedFlags();
+ if (supportedFlags != -1 && unsupportedFlags != -1) {
+ return checkAppMediaSupport(supportedFlags, unsupportedFlags, fileFlags,
+ "cached_app_manifest");
+ }
+
+ try {
+ Property mediaCapProperty = mPackageManager.getProperty(
+ PackageManager.PROPERTY_MEDIA_CAPABILITIES, packageName);
+ XmlResourceParser parser = mPackageManager.getResourcesForApplication(packageName)
+ .getXml(mediaCapProperty.getResourceId());
+ ApplicationMediaCapabilities capability = ApplicationMediaCapabilities.createFromXml(
+ parser);
+ Pair<Integer, Integer> flags = capabilitiesToMediaFormatFlags(capability);
+ supportedFlags = flags.first;
+ unsupportedFlags = flags.second;
+ identity.setApplicationMediaCapabilitiesFlags(supportedFlags, unsupportedFlags);
+
+ return checkAppMediaSupport(supportedFlags, unsupportedFlags, fileFlags,
+ "app_manifest");
+ } catch (PackageManager.NameNotFoundException | UnsupportedOperationException e) {
+ return Optional.empty();
+ }
+ }
+
+ @ApplicationMediaCapabilitiesFlags
+ private Pair<Integer, Integer> capabilitiesToMediaFormatFlags(
+ ApplicationMediaCapabilities capability) {
+ int supportedFlags = 0;
+ int unsupportedFlags = 0;
+
+ // MimeType
+ if (capability.isFormatSpecified(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
+ if (capability.isVideoMimeTypeSupported(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
+ supportedFlags |= FLAG_HEVC;
+ } else {
+ unsupportedFlags |= FLAG_HEVC;
+ }
+ }
+
+ // HdrType
+ if (capability.isFormatSpecified(MediaFeature.HdrType.HDR10)) {
+ if (capability.isHdrTypeSupported(MediaFeature.HdrType.HDR10)) {
+ supportedFlags |= FLAG_HDR_10;
+ } else {
+ unsupportedFlags |= FLAG_HDR_10;
+ }
+ }
+
+ if (capability.isFormatSpecified(MediaFeature.HdrType.HDR10_PLUS)) {
+ if (capability.isHdrTypeSupported(MediaFeature.HdrType.HDR10_PLUS)) {
+ supportedFlags |= FLAG_HDR_10_PLUS;
+ } else {
+ unsupportedFlags |= FLAG_HDR_10_PLUS;
+ }
+ }
+
+ if (capability.isFormatSpecified(MediaFeature.HdrType.HLG)) {
+ if (capability.isHdrTypeSupported(MediaFeature.HdrType.HLG)) {
+ supportedFlags |= FLAG_HDR_HLG;
+ } else {
+ unsupportedFlags |= FLAG_HDR_HLG;
+ }
+ }
+
+ if (capability.isFormatSpecified(MediaFeature.HdrType.DOLBY_VISION)) {
+ if (capability.isHdrTypeSupported(MediaFeature.HdrType.DOLBY_VISION)) {
+ supportedFlags |= FLAG_HDR_DOLBY_VISION;
+ } else {
+ unsupportedFlags |= FLAG_HDR_DOLBY_VISION;
+ }
+ }
+
+ return Pair.create(supportedFlags, unsupportedFlags);
+ }
+
+ private boolean getBooleanProperty(String sysPropKey, String deviceConfigKey,
+ boolean defaultValue) {
+ // If the user wants to override the default, respect that; otherwise use the DeviceConfig
+ // which is filled with the values sent from server.
+ if (SystemProperties.getBoolean(TRANSCODE_USER_CONTROL_SYS_PROP_KEY, false)) {
+ return SystemProperties.getBoolean(sysPropKey, defaultValue);
+ }
+
+ return mMediaProvider.getBooleanDeviceConfig(deviceConfigKey, defaultValue);
+ }
+
+ private Pair<Long, Integer> getTranscodeCacheInfoFromDB(String path) {
+ try (Cursor cursor = queryFileForTranscode(path, TRANSCODE_CACHE_INFO_PROJECTION)) {
+ if (cursor != null && cursor.moveToNext()) {
+ return Pair.create(cursor.getLong(0), cursor.getInt(1));
+ }
+ }
+ return Pair.create((long) -1, TRANSCODE_EMPTY);
+ }
+
+ // called from MediaProvider
+ void onUriPublished(Uri uri) {
+ if (!isTranscodeEnabled()) {
+ return;
+ }
+
+ try (Cursor c = mMediaProvider.queryForSingleItem(uri,
+ new String[]{
+ FileColumns._VIDEO_CODEC_TYPE,
+ FileColumns.SIZE,
+ FileColumns.OWNER_PACKAGE_NAME,
+ FileColumns.DATA,
+ MediaColumns.DURATION,
+ MediaColumns.CAPTURE_FRAMERATE,
+ MediaColumns.WIDTH,
+ MediaColumns.HEIGHT
+ },
+ null, null, null)) {
+ if (supportsTranscode(c.getString(3))) {
+ if (isHevc(c.getString(0))) {
+ MediaProviderStatsLog.write(
+ TRANSCODING_DATA,
+ c.getString(2) /* owner_package_name */,
+ MediaProviderStatsLog.TRANSCODING_DATA__ACCESS_TYPE__HEVC_WRITE,
+ c.getLong(1) /* file size */,
+ TRANSCODING_DATA__TRANSCODE_RESULT__UNDEFINED,
+ -1 /* transcoding_duration */,
+ c.getLong(4) /* video_duration */,
+ c.getLong(5) /* capture_framerate */,
+ -1 /* transcode_reason */,
+ c.getLong(6) /* width */,
+ c.getLong(7) /* height */,
+ false /* hit_anr */,
+ TRANSCODING_DATA__FAILURE_CAUSE__CAUSE_UNKNOWN,
+ TranscodingSession.ERROR_NONE);
+
+ } else {
+ MediaProviderStatsLog.write(
+ TRANSCODING_DATA,
+ c.getString(2) /* owner_package_name */,
+ MediaProviderStatsLog.TRANSCODING_DATA__ACCESS_TYPE__AVC_WRITE,
+ c.getLong(1) /* file size */,
+ TRANSCODING_DATA__TRANSCODE_RESULT__UNDEFINED,
+ -1 /* transcoding_duration */,
+ c.getLong(4) /* video_duration */,
+ c.getLong(5) /* capture_framerate */,
+ -1 /* transcode_reason */,
+ c.getLong(6) /* width */,
+ c.getLong(7) /* height */,
+ false /* hit_anr */,
+ TRANSCODING_DATA__FAILURE_CAUSE__CAUSE_UNKNOWN,
+ TranscodingSession.ERROR_NONE);
+ }
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "Couldn't get cursor for scanned file", e);
+ }
+ }
+
+ void onFileOpen(String path, String ioPath, int uid, int transformsReason) {
+ if (!isTranscodeEnabled()) {
+ return;
+ }
+
+ String[] resolverInfoProjection = new String[] {
+ FileColumns._VIDEO_CODEC_TYPE,
+ FileColumns.SIZE,
+ MediaColumns.DURATION,
+ MediaColumns.CAPTURE_FRAMERATE,
+ MediaColumns.WIDTH,
+ MediaColumns.HEIGHT,
+ VideoColumns.COLOR_STANDARD,
+ VideoColumns.COLOR_TRANSFER
+ };
+
+ try (Cursor c = queryFileForTranscode(path, resolverInfoProjection)) {
+ if (c != null && c.moveToNext()) {
+ if (supportsTranscode(path)
+ && isModernFormat(c.getString(0), c.getInt(6), c.getInt(7))) {
+ if (transformsReason == 0) {
+ MediaProviderStatsLog.write(
+ TRANSCODING_DATA,
+ getMetricsSafeNameForUid(uid) /* owner_package_name */,
+ MediaProviderStatsLog.TRANSCODING_DATA__ACCESS_TYPE__READ_DIRECT,
+ c.getLong(1) /* file size */,
+ TRANSCODING_DATA__TRANSCODE_RESULT__UNDEFINED,
+ -1 /* transcoding_duration */,
+ c.getLong(2) /* video_duration */,
+ c.getLong(3) /* capture_framerate */,
+ -1 /* transcode_reason */,
+ c.getLong(4) /* width */,
+ c.getLong(5) /* height */,
+ false /*hit_anr*/,
+ TRANSCODING_DATA__FAILURE_CAUSE__CAUSE_UNKNOWN,
+ TranscodingSession.ERROR_NONE);
+ } else if (isTranscodeFileCached(path, ioPath)) {
+ MediaProviderStatsLog.write(
+ TRANSCODING_DATA,
+ getMetricsSafeNameForUid(uid) /* owner_package_name */,
+ MediaProviderStatsLog.TRANSCODING_DATA__ACCESS_TYPE__READ_CACHE,
+ c.getLong(1) /* file size */,
+ TRANSCODING_DATA__TRANSCODE_RESULT__UNDEFINED,
+ -1 /* transcoding_duration */,
+ c.getLong(2) /* video_duration */,
+ c.getLong(3) /* capture_framerate */,
+ transformsReason /* transcode_reason */,
+ c.getLong(4) /* width */,
+ c.getLong(5) /* height */,
+ false /*hit_anr*/,
+ TRANSCODING_DATA__FAILURE_CAUSE__CAUSE_UNKNOWN,
+ TranscodingSession.ERROR_NONE);
+ } // else if file is not in cache, we'll log at read(2) when we transcode
+ }
+ }
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Unable to log metrics on file open", e);
+ }
+ }
+
+ public boolean isTranscodeFileCached(String path, String transcodePath) {
+ // This can only happen when we are in a version that supports transcoding.
+ // So, no need to check for the SDK version here.
+
+ if (SystemProperties.getBoolean("persist.sys.fuse.disable_transcode_cache", false)) {
+ // Caching is disabled. Hence, delete the cached transcode file.
+ return false;
+ }
+
+ Pair<Long, Integer> cacheInfo = getTranscodeCacheInfoFromDB(path);
+ final long rowId = cacheInfo.first;
+ if (rowId != -1) {
+ final int transcodeStatus = cacheInfo.second;
+ boolean result = transcodePath.equalsIgnoreCase(getTranscodePath(rowId)) &&
+ transcodeStatus == TRANSCODE_COMPLETE &&
+ new File(transcodePath).exists();
+ if (result) {
+ logEvent("Transcode cache hit: " + path, null /* session */);
+ }
+ return result;
+ }
+ return false;
+ }
+
+ @Nullable
+ private MediaFormat getVideoTrackFormat(String path) {
+ String[] resolverInfoProjection = new String[]{
+ FileColumns._VIDEO_CODEC_TYPE,
+ MediaStore.MediaColumns.WIDTH,
+ MediaStore.MediaColumns.HEIGHT,
+ MediaStore.MediaColumns.BITRATE,
+ MediaStore.MediaColumns.CAPTURE_FRAMERATE
+ };
+ try (Cursor c = queryFileForTranscode(path, resolverInfoProjection)) {
+ if (c != null && c.moveToNext()) {
+ String codecType = c.getString(0);
+ int width = c.getInt(1);
+ int height = c.getInt(2);
+ int bitRate = c.getInt(3);
+ float framerate = c.getFloat(4);
+
+ // TODO(b/169849854): Get this info from Manifest, for now if app got here it
+ // definitely doesn't support hevc
+ ApplicationMediaCapabilities capability =
+ new ApplicationMediaCapabilities.Builder().build();
+ MediaFormat sourceFormat = MediaFormat.createVideoFormat(
+ codecType, width, height);
+ if (framerate > 0) {
+ sourceFormat.setFloat(MediaFormat.KEY_FRAME_RATE, framerate);
+ }
+ VideoFormatResolver resolver = new VideoFormatResolver(capability, sourceFormat);
+ MediaFormat resolvedFormat = resolver.resolveVideoFormat();
+ resolvedFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
+
+ return resolvedFormat;
+ }
+ }
+ throw new IllegalStateException("Couldn't get video format info from database for " + path);
+ }
+
+ private TranscodingSession enqueueTranscodingSession(String src, String dst, int uid,
+ final CountDownLatch latch) throws UnsupportedOperationException, IOException {
+ // Fetch the service lazily to improve memory usage
+ final MediaTranscodeManager mediaTranscodeManager =
+ mContext.getSystemService(MediaTranscodeManager.class);
+ File file = new File(src);
+ File transcodeFile = new File(dst);
+
+ // These are file URIs (effectively file paths) and even if the |transcodeFile| is
+ // inaccesible via FUSE, it works because the transcoding service calls into the
+ // MediaProvider to open them and within the MediaProvider, it is opened directly on
+ // the lower fs.
+ Uri uri = Uri.fromFile(file);
+ Uri transcodeUri = Uri.fromFile(transcodeFile);
+
+ ParcelFileDescriptor srcPfd = ParcelFileDescriptor.open(file,
+ ParcelFileDescriptor.MODE_READ_ONLY);
+ ParcelFileDescriptor dstPfd = ParcelFileDescriptor.open(transcodeFile,
+ ParcelFileDescriptor.MODE_READ_WRITE);
+
+ MediaFormat format = getVideoTrackFormat(src);
+
+ VideoTranscodingRequest request =
+ new VideoTranscodingRequest.Builder(uri, transcodeUri, format)
+ .setClientUid(uid)
+ .setSourceFileDescriptor(srcPfd)
+ .setDestinationFileDescriptor(dstPfd)
+ .build();
+ TranscodingSession session = mediaTranscodeManager.enqueueRequest(request,
+ ForegroundThread.getExecutor(),
+ s -> {
+ mTranscodingUiNotifier.stop(s, src);
+ finishTranscodingResult(uid, src, s, latch);
+ mSessionTiming.logSessionEnd(s);
+ });
+ session.setOnProgressUpdateListener(ForegroundThread.getExecutor(),
+ (s, progress) -> mTranscodingUiNotifier.setProgress(s, src, progress));
+
+ mSessionTiming.logSessionStart(session);
+ mTranscodingUiNotifier.start(session, src);
+ logEvent("Transcoding start: " + src + ". Uid: " + uid, session);
+ return session;
+ }
+
+ /**
+ * Returns an {@link Integer} indicating whether the transcoding {@code session} was successful
+ * or not.
+ *
+ * @return {@link TRANSCODING_DATA__FAILURE_CAUSE__CAUSE_UNKNOWN} on success,
+ * otherwise indicates failure.
+ */
+ private int waitTranscodingResult(int uid, String src, TranscodingSession session,
+ CountDownLatch latch) {
+ UUID uuid = getTranscodeVolumeUuid();
+ try {
+ if (uuid != null) {
+ // tid is 0 since we can't really get the apps tid over binder
+ mStorageManager.notifyAppIoBlocked(uuid, uid, 0 /* tid */,
+ StorageManager.APP_IO_BLOCKED_REASON_TRANSCODING);
+ }
+
+ int timeout = getTranscodeTimeoutSeconds(src);
+
+ String waitStartLog = "Transcoding wait start: " + src + ". Uid: " + uid + ". Timeout: "
+ + timeout + "s";
+ logEvent(waitStartLog, session);
+
+ boolean latchResult = latch.await(timeout, TimeUnit.SECONDS);
+ int sessionResult = session.getResult();
+ boolean transcodeResult = sessionResult == TranscodingSession.RESULT_SUCCESS;
+
+ String waitEndLog = "Transcoding wait end: " + src + ". Uid: " + uid + ". Timeout: "
+ + !latchResult + ". Success: " + transcodeResult;
+ logEvent(waitEndLog, session);
+
+ if (sessionResult == TranscodingSession.RESULT_SUCCESS) {
+ return TRANSCODING_DATA__FAILURE_CAUSE__CAUSE_UNKNOWN;
+ } else if (sessionResult == TranscodingSession.RESULT_CANCELED) {
+ return TRANSCODING_DATA__FAILURE_CAUSE__TRANSCODING_SESSION_CANCELED;
+ } else if (!latchResult) {
+ return TRANSCODING_DATA__FAILURE_CAUSE__TRANSCODING_CLIENT_TIMEOUT;
+ } else {
+ return TRANSCODING_DATA__FAILURE_CAUSE__TRANSCODING_SERVICE_ERROR;
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ Log.w(TAG, "Transcoding latch interrupted." + session);
+ return TRANSCODING_DATA__FAILURE_CAUSE__TRANSCODING_CLIENT_TIMEOUT;
+ } finally {
+ if (uuid != null) {
+ // tid is 0 since we can't really get the apps tid over binder
+ mStorageManager.notifyAppIoResumed(uuid, uid, 0 /* tid */,
+ StorageManager.APP_IO_BLOCKED_REASON_TRANSCODING);
+ }
+ }
+ }
+
+ private int getTranscodeTimeoutSeconds(String file) {
+ double sizeMb = (new File(file).length() / (1024 * 1024));
+ // Ensure size is at least 1MB so transcoding timeout is at least the timeout coefficient
+ sizeMb = Math.max(sizeMb, 1);
+ return (int) (sizeMb * TRANSCODING_TIMEOUT_COEFFICIENT);
+ }
+
+ private void finishTranscodingResult(int uid, String src, TranscodingSession session,
+ CountDownLatch latch) {
+ final StorageTranscodingSession finishedSession;
+
+ synchronized (mLock) {
+ latch.countDown();
+ session.cancel();
+
+ finishedSession = mStorageTranscodingSessions.remove(src);
+
+ switch (session.getResult()) {
+ case TranscodingSession.RESULT_SUCCESS:
+ mSuccessfulTranscodeSessions.put(finishedSession, false /* placeholder */);
+ break;
+ case TranscodingSession.RESULT_CANCELED:
+ mCancelledTranscodeSessions.put(finishedSession, false /* placeholder */);
+ break;
+ case TranscodingSession.RESULT_ERROR:
+ mErroredTranscodeSessions.put(finishedSession, false /* placeholder */);
+ break;
+ default:
+ Log.w(TAG, "TranscodingSession.RESULT_NONE received for a finished session");
+ }
+ }
+
+ logEvent("Transcoding end: " + src + ". Uid: " + uid, session);
+ }
+
+ private boolean updateTranscodeStatus(String path, int transcodeStatus) {
+ final Uri uri = FileUtils.getContentUriForPath(path);
+ // TODO(b/170465810): Replace this with matchUri when the code is refactored.
+ final int match = MediaProvider.FILES;
+ final SQLiteQueryBuilder qb = mMediaProvider.getQueryBuilderForTranscoding(TYPE_UPDATE,
+ match, uri, Bundle.EMPTY, null);
+ final String[] selectionArgs = new String[]{path};
+
+ ContentValues values = new ContentValues();
+ values.put(FileColumns._TRANSCODE_STATUS, transcodeStatus);
+ final boolean success = qb.update(getDatabaseHelperForUri(uri), values,
+ TRANSCODE_WHERE_CLAUSE, selectionArgs) == 1;
+ if (!success) {
+ Log.w(TAG, "Transcoding status update to: " + transcodeStatus + " failed for " + path);
+ }
+ return success;
+ }
+
+ public boolean deleteCachedTranscodeFile(long rowId) {
+ return new File(mTranscodeDirectory, String.valueOf(rowId)).delete();
+ }
+
+ private DatabaseHelper getDatabaseHelperForUri(Uri uri) {
+ final DatabaseHelper helper;
+ try {
+ return mMediaProvider.getDatabaseForUriForTranscoding(uri);
+ } catch (VolumeNotFoundException e) {
+ throw new IllegalStateException("Volume not found while querying transcode path", e);
+ }
+ }
+
+ /**
+ * @return given {@code projection} columns from database for given {@code path}.
+ * Note that cursor might be empty if there is no database row or file is pending or trashed.
+ * TODO(b/170465810): Optimize these queries by bypassing getQueryBuilder(). These queries are
+ * always on Files table and doesn't have any dependency on calling package. i.e., query is
+ * always called with callingPackage=self.
+ */
+ @Nullable
+ private Cursor queryFileForTranscode(String path, String[] projection) {
+ final Uri uri = FileUtils.getContentUriForPath(path);
+ // TODO(b/170465810): Replace this with matchUri when the code is refactored.
+ final int match = MediaProvider.FILES;
+ final SQLiteQueryBuilder qb = mMediaProvider.getQueryBuilderForTranscoding(TYPE_QUERY,
+ match, uri, Bundle.EMPTY, null);
+ final String[] selectionArgs = new String[]{path};
+
+ Bundle extras = new Bundle();
+ extras.putInt(QUERY_ARG_MATCH_PENDING, MATCH_EXCLUDE);
+ extras.putInt(QUERY_ARG_MATCH_TRASHED, MATCH_EXCLUDE);
+ extras.putString(ContentResolver.QUERY_ARG_SQL_SELECTION, TRANSCODE_WHERE_CLAUSE);
+ extras.putStringArray(ContentResolver.QUERY_ARG_SQL_SELECTION_ARGS, selectionArgs);
+ return qb.query(getDatabaseHelperForUri(uri), projection, extras, null);
+ }
+
+ private boolean isTranscodeEnabled() {
+ return IS_TRANSCODING_SUPPORTED && getBooleanProperty(TRANSCODE_ENABLED_SYS_PROP_KEY,
+ TRANSCODE_ENABLED_DEVICE_CONFIG_KEY, true /* defaultValue */);
+ }
+
+ private boolean shouldTranscodeDefault() {
+ return getBooleanProperty(TRANSCODE_DEFAULT_SYS_PROP_KEY,
+ TRANSCODE_DEFAULT_DEVICE_CONFIG_KEY, false /* defaultValue */);
+ }
+
+ private void updateConfigs(boolean transcodeEnabled) {
+ synchronized (mLock) {
+ boolean isTranscodeEnabledChanged = transcodeEnabled != mIsTranscodeEnabled;
+
+ if (isTranscodeEnabledChanged) {
+ Log.i(TAG, "Reloading transcode configs. transcodeEnabled: " + transcodeEnabled
+ + ". lastTranscodeEnabled: " + mIsTranscodeEnabled);
+
+ mIsTranscodeEnabled = transcodeEnabled;
+ parseTranscodeCompatManifest();
+ }
+ }
+ }
+
+ private void parseTranscodeCompatManifest() {
+ synchronized (mLock) {
+ // Clear the transcode_compat manifest before parsing. If transcode is disabled,
+ // nothing will be parsed, effectively leaving the compat manifest empty.
+ mAppCompatMediaCapabilities.clear();
+ if (!mIsTranscodeEnabled) {
+ return;
+ }
+
+ Set<String> stalePackages = getTranscodeCompatStale();
+ parseTranscodeCompatManifestFromResourceLocked(stalePackages);
+ parseTranscodeCompatManifestFromDeviceConfigLocked();
+ }
+ }
+
+ /** @return {@code true} if the manifest was parsed successfully, {@code false} otherwise */
+ private boolean parseTranscodeCompatManifestFromDeviceConfigLocked() {
+ final String[] manifest = mMediaProvider.getStringDeviceConfig(
+ TRANSCODE_COMPAT_MANIFEST_KEY, "").split(",");
+
+ if (manifest.length == 0 || manifest[0].isEmpty()) {
+ Log.i(TAG, "Empty device config transcode compat manifest");
+ return false;
+ }
+ if ((manifest.length % 2) != 0) {
+ Log.w(TAG, "Uneven number of items in device config transcode compat manifest");
+ return false;
+ }
+
+ String packageName = "";
+ int packageCompatValue;
+ int i = 0;
+ int count = 0;
+ while (i < manifest.length - 1) {
+ try {
+ packageName = manifest[i++];
+ packageCompatValue = Integer.parseInt(manifest[i++]);
+ synchronized (mLock) {
+ // Lock is already held, explicitly hold again to make error prone happy
+ mAppCompatMediaCapabilities.put(packageName, packageCompatValue);
+ count++;
+ }
+ } catch (NumberFormatException e) {
+ Log.w(TAG, "Failed to parse media capability from device config for package: "
+ + packageName, e);
+ }
+ }
+
+ Log.i(TAG, "Parsed " + count + " packages from device config");
+ return count != 0;
+ }
+
+ /** @return {@code true} if the manifest was parsed successfully, {@code false} otherwise */
+ private boolean parseTranscodeCompatManifestFromResourceLocked(Set<String> stalePackages) {
+ InputStream inputStream = mContext.getResources().openRawResource(
+ R.raw.transcode_compat_manifest);
+ BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
+ int count = 0;
+ try {
+ while (reader.ready()) {
+ String line = reader.readLine();
+ String packageName = "";
+ int packageCompatValue;
+
+ if (line == null) {
+ Log.w(TAG, "Unexpected null line while parsing transcode compat manifest");
+ continue;
+ }
+
+ String[] lineValues = line.split(",");
+ if (lineValues.length != 2) {
+ Log.w(TAG, "Failed to read line while parsing transcode compat manifest");
+ continue;
+ }
+ try {
+ packageName = lineValues[0];
+ packageCompatValue = Integer.parseInt(lineValues[1]);
+
+ if (stalePackages.contains(packageName)) {
+ Log.i(TAG, "Skipping stale package in transcode compat manifest: "
+ + packageName);
+ continue;
+ }
+
+ synchronized (mLock) {
+ // Lock is already held, explicitly hold again to make error prone happy
+ mAppCompatMediaCapabilities.put(packageName, packageCompatValue);
+ count++;
+ }
+ } catch (NumberFormatException e) {
+ Log.w(TAG, "Failed to parse media capability from resource for package: "
+ + packageName, e);
+ }
+ }
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to read transcode compat manifest", e);
+ }
+
+ Log.i(TAG, "Parsed " + count + " packages from resource");
+ return count != 0;
+ }
+
+ private Set<String> getTranscodeCompatStale() {
+ Set<String> stalePackages = new ArraySet<>();
+ final String[] staleConfig = mMediaProvider.getStringDeviceConfig(
+ TRANSCODE_COMPAT_STALE_KEY, "").split(",");
+
+ if (staleConfig.length == 0 || staleConfig[0].isEmpty()) {
+ Log.i(TAG, "Empty transcode compat stale");
+ return stalePackages;
+ }
+
+ for (String stalePackage : staleConfig) {
+ stalePackages.add(stalePackage);
+ }
+
+ int size = stalePackages.size();
+ Log.i(TAG, "Parsed " + size + " stale packages from device config");
+ return stalePackages;
+ }
+
+ public void dump(PrintWriter writer) {
+ writer.println("isTranscodeEnabled=" + isTranscodeEnabled());
+ writer.println("shouldTranscodeDefault=" + shouldTranscodeDefault());
+
+ synchronized (mLock) {
+ writer.println("mAppCompatMediaCapabilities=" + mAppCompatMediaCapabilities);
+ writer.println("mStorageTranscodingSessions=" + mStorageTranscodingSessions);
+
+ dumpFinishedSessions(writer);
+ }
+ }
+
+ private void dumpFinishedSessions(PrintWriter writer) {
+ synchronized (mLock) {
+ writer.println("mSuccessfulTranscodeSessions=" + mSuccessfulTranscodeSessions.keySet());
+
+ writer.println("mCancelledTranscodeSessions=" + mCancelledTranscodeSessions.keySet());
+
+ writer.println("mErroredTranscodeSessions=" + mErroredTranscodeSessions.keySet());
+ }
+ }
+
+ private static void logEvent(String event, @Nullable TranscodingSession session) {
+ Log.d(TAG, event + (session == null ? "" : session));
+ }
+
+ private static void logVerbose(String message) {
+ if (DEBUG) {
+ Log.v(TAG, message);
+ }
+ }
+
+ // We want to keep track of only the most recent [MAX_FINISHED_TRANSCODING_SESSION_STORE_COUNT]
+ // finished transcoding sessions.
+ private static LinkedHashMap createFinishedTranscodingSessionMap() {
+ return new LinkedHashMap<StorageTranscodingSession, Boolean>() {
+ @Override
+ protected boolean removeEldestEntry(Entry eldest) {
+ return size() > MAX_FINISHED_TRANSCODING_SESSION_STORE_COUNT;
+ }
+ };
+ }
+
+ @VisibleForTesting
+ static int getMyUid() {
+ return MY_UID;
+ }
+
+ private static class StorageTranscodingSession {
+ private static final DateTimeFormatter DATE_FORMAT =
+ DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
+
+ public final TranscodingSession session;
+ public final CountDownLatch latch;
+ private final String mSrcPath;
+ private final String mDstPath;
+ @GuardedBy("latch")
+ private final Set<Integer> mBlockedUids = new ArraySet<>();
+ private final LocalDateTime mStartTime;
+ @GuardedBy("latch")
+ private LocalDateTime mFinishTime;
+ @GuardedBy("latch")
+ private boolean mHasAnr;
+ @GuardedBy("latch")
+ private int mFailureReason;
+ @GuardedBy("latch")
+ private int mErrorCode;
+
+ public StorageTranscodingSession(TranscodingSession session, CountDownLatch latch,
+ String srcPath, String dstPath) {
+ this.session = session;
+ this.latch = latch;
+ this.mSrcPath = srcPath;
+ this.mDstPath = dstPath;
+ this.mStartTime = LocalDateTime.now();
+ mErrorCode = TranscodingSession.ERROR_NONE;
+ mFailureReason = TRANSCODING_DATA__FAILURE_CAUSE__CAUSE_UNKNOWN;
+ }
+
+ public void addBlockedUid(int uid) {
+ session.addClientUid(uid);
+ }
+
+ public boolean isUidBlocked(int uid) {
+ return session.getClientUids().contains(uid);
+ }
+
+ public void setAnr() {
+ synchronized (latch) {
+ mHasAnr = true;
+ }
+ }
+
+ public boolean hasAnr() {
+ synchronized (latch) {
+ return mHasAnr;
+ }
+ }
+
+ public void notifyFinished(int failureReason, int errorCode) {
+ synchronized (latch) {
+ mFinishTime = LocalDateTime.now();
+ mFailureReason = failureReason;
+ mErrorCode = errorCode;
+ }
+ }
+
+ @Override
+ public String toString() {
+ String startTime = mStartTime.format(DATE_FORMAT);
+ String finishTime = "NONE";
+ String durationMs = "NONE";
+ boolean hasAnr;
+ int failureReason;
+ int errorCode;
+
+ synchronized (latch) {
+ if (mFinishTime != null) {
+ finishTime = mFinishTime.format(DATE_FORMAT);
+ durationMs = String.valueOf(mStartTime.until(mFinishTime, ChronoUnit.MILLIS));
+ }
+ hasAnr = mHasAnr;
+ failureReason = mFailureReason;
+ errorCode = mErrorCode;
+ }
+
+ return String.format("<%s. Src: %s. Dst: %s. BlockedUids: %s. DurationMs: %sms"
+ + ". Start: %s. Finish: %sms. HasAnr: %b. FailureReason: %d. ErrorCode: %d>",
+ session.toString(), mSrcPath, mDstPath, session.getClientUids(), durationMs,
+ startTime, finishTime, hasAnr, failureReason, errorCode);
+ }
+ }
+
+ private static class TranscodeUiNotifier {
+ private static final int PROGRESS_MAX = 100;
+ private static final int ALERT_DISMISS_DELAY_MS = 1000;
+ private static final int SHOW_PROGRESS_THRESHOLD_TIME_MS = 1000;
+ private static final String TRANSCODE_ALERT_CHANNEL_ID = "native_transcode_alert_channel";
+ private static final String TRANSCODE_ALERT_CHANNEL_NAME = "Native Transcode Alerts";
+ private static final String TRANSCODE_PROGRESS_CHANNEL_ID =
+ "native_transcode_progress_channel";
+ private static final String TRANSCODE_PROGRESS_CHANNEL_NAME = "Native Transcode Progress";
+
+ // Related to notification settings
+ private static final String TRANSCODE_NOTIFICATION_SYS_PROP_KEY =
+ "persist.sys.fuse.transcode_notification";
+ private static final boolean NOTIFICATION_ALLOWED_DEFAULT_VALUE = true;
+
+ private final Context mContext;
+ private final NotificationManagerCompat mNotificationManager;
+ private final PackageManager mPackageManager;
+ // Builder for creating alert notifications.
+ private final NotificationCompat.Builder mAlertBuilder;
+ // Builder for creating progress notifications.
+ private final NotificationCompat.Builder mProgressBuilder;
+ private final SessionTiming mSessionTiming;
+
+ TranscodeUiNotifier(Context context, SessionTiming sessionTiming) {
+ mContext = context;
+ mNotificationManager = NotificationManagerCompat.from(context);
+ mPackageManager = context.getPackageManager();
+ createAlertNotificationChannel(context);
+ createProgressNotificationChannel(context);
+ mAlertBuilder = createAlertNotificationBuilder(context);
+ mProgressBuilder = createProgressNotificationBuilder(context);
+ mSessionTiming = sessionTiming;
+ }
+
+ void start(TranscodingSession session, String filePath) {
+ if (!notificationEnabled()) {
+ return;
+ }
+ ForegroundThread.getHandler().post(() -> {
+ mAlertBuilder.setContentTitle(getString(mContext,
+ R.string.transcode_processing_started));
+ mAlertBuilder.setContentText(FileUtils.extractDisplayName(filePath));
+ final int notificationId = session.getSessionId();
+ mNotificationManager.notify(notificationId, mAlertBuilder.build());
+ });
+ }
+
+ void stop(TranscodingSession session, String filePath) {
+ if (!notificationEnabled()) {
+ return;
+ }
+ endSessionWithMessage(session, filePath, getResultMessageForSession(mContext, session));
+ }
+
+ void denied(int uid) {
+ String appName = getAppName(uid);
+ if (appName == null) {
+ Log.w(TAG, "Not showing denial, no app name ");
+ return;
+ }
+
+ final Handler handler = ForegroundThread.getHandler();
+ handler.post(() -> {
+ Toast.makeText(mContext,
+ mContext.getResources().getString(R.string.transcode_denied, appName),
+ Toast.LENGTH_LONG).show();
+ });
+ }
+
+ void setProgress(TranscodingSession session, String filePath,
+ @IntRange(from = 0, to = PROGRESS_MAX) int progress) {
+ if (!notificationEnabled()) {
+ return;
+ }
+ if (shouldShowProgress(session)) {
+ mProgressBuilder.setContentText(FileUtils.extractDisplayName(filePath));
+ mProgressBuilder.setProgress(PROGRESS_MAX, progress, /* indeterminate= */ false);
+ final int notificationId = session.getSessionId();
+ mNotificationManager.notify(notificationId, mProgressBuilder.build());
+ }
+ }
+
+ private boolean shouldShowProgress(TranscodingSession session) {
+ return (System.currentTimeMillis() - mSessionTiming.getSessionStartTime(session))
+ > SHOW_PROGRESS_THRESHOLD_TIME_MS;
+ }
+
+ private void endSessionWithMessage(TranscodingSession session, String filePath,
+ String message) {
+ final Handler handler = ForegroundThread.getHandler();
+ handler.post(() -> {
+ mAlertBuilder.setContentTitle(message);
+ mAlertBuilder.setContentText(FileUtils.extractDisplayName(filePath));
+ final int notificationId = session.getSessionId();
+ mNotificationManager.notify(notificationId, mAlertBuilder.build());
+ // Auto-dismiss after a delay.
+ handler.postDelayed(() -> mNotificationManager.cancel(notificationId),
+ ALERT_DISMISS_DELAY_MS);
+ });
+ }
+
+ private String getAppName(int uid) {
+ String name = mPackageManager.getNameForUid(uid);
+ if (name == null) {
+ Log.w(TAG, "Couldn't find name");
+ return null;
+ }
+
+ final ApplicationInfo aInfo;
+ try {
+ aInfo = mPackageManager.getApplicationInfo(name, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "unable to look up package name", e);
+ return null;
+ }
+
+ // If the label contains new line characters it may push the security
+ // message below the fold of the dialog. Labels shouldn't have new line
+ // characters anyways, so we just delete all of the newlines (if there are any).
+ return aInfo.loadSafeLabel(mPackageManager, MAX_APP_NAME_SIZE_PX,
+ TextUtils.SAFE_STRING_FLAG_SINGLE_LINE).toString();
+ }
+
+ private static String getString(Context context, int resourceId) {
+ return context.getResources().getString(resourceId);
+ }
+
+ private static void createAlertNotificationChannel(Context context) {
+ NotificationChannel channel = new NotificationChannel(TRANSCODE_ALERT_CHANNEL_ID,
+ TRANSCODE_ALERT_CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH);
+ NotificationManager notificationManager = context.getSystemService(
+ NotificationManager.class);
+ notificationManager.createNotificationChannel(channel);
+ }
+
+ private static void createProgressNotificationChannel(Context context) {
+ NotificationChannel channel = new NotificationChannel(TRANSCODE_PROGRESS_CHANNEL_ID,
+ TRANSCODE_PROGRESS_CHANNEL_NAME, NotificationManager.IMPORTANCE_LOW);
+ NotificationManager notificationManager = context.getSystemService(
+ NotificationManager.class);
+ notificationManager.createNotificationChannel(channel);
+ }
+
+ private static NotificationCompat.Builder createAlertNotificationBuilder(Context context) {
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(context,
+ TRANSCODE_ALERT_CHANNEL_ID);
+ builder.setAutoCancel(false)
+ .setOngoing(true)
+ .setSmallIcon(R.drawable.thumb_clip);
+ return builder;
+ }
+
+ private static NotificationCompat.Builder createProgressNotificationBuilder(
+ Context context) {
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(context,
+ TRANSCODE_PROGRESS_CHANNEL_ID);
+ builder.setAutoCancel(false)
+ .setOngoing(true)
+ .setContentTitle(getString(context, R.string.transcode_processing))
+ .setSmallIcon(R.drawable.thumb_clip);
+ return builder;
+ }
+
+ private static String getResultMessageForSession(Context context,
+ TranscodingSession session) {
+ switch (session.getResult()) {
+ case TranscodingSession.RESULT_CANCELED:
+ return getString(context, R.string.transcode_processing_cancelled);
+ case TranscodingSession.RESULT_ERROR:
+ return getString(context, R.string.transcode_processing_error);
+ case TranscodingSession.RESULT_SUCCESS:
+ return getString(context, R.string.transcode_processing_success);
+ default:
+ return getString(context, R.string.transcode_processing_error);
+ }
+ }
+
+ private static boolean notificationEnabled() {
+ return SystemProperties.getBoolean(TRANSCODE_NOTIFICATION_SYS_PROP_KEY,
+ NOTIFICATION_ALLOWED_DEFAULT_VALUE);
+ }
+ }
+
+ private static class TranscodeDenialController implements OnUidImportanceListener {
+ private final int mMaxDurationMs;
+ private final ActivityManager mActivityManager;
+ private final TranscodeUiNotifier mUiNotifier;
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
+ private final Set<Integer> mActiveDeniedUids = new ArraySet<>();
+ @GuardedBy("mLock")
+ private final Set<Integer> mDroppedUids = new ArraySet<>();
+
+ TranscodeDenialController(ActivityManager activityManager, TranscodeUiNotifier uiNotifier,
+ int maxDurationMs) {
+ mActivityManager = activityManager;
+ mUiNotifier = uiNotifier;
+ mMaxDurationMs = maxDurationMs;
+ }
+
+ @Override
+ public void onUidImportance(int uid, int importance) {
+ if (importance != IMPORTANCE_FOREGROUND) {
+ synchronized (mLock) {
+ if (mActiveDeniedUids.remove(uid) && mActiveDeniedUids.isEmpty()) {
+ // Stop the uid listener if this is the last uid triggering a denial UI
+ mActivityManager.removeOnUidImportanceListener(this);
+ }
+ }
+ }
+ }
+
+ /** @return {@code true} if file access should be denied, {@code false} otherwise */
+ boolean checkFileAccess(int uid, long durationMs) {
+ boolean shouldDeny = false;
+ synchronized (mLock) {
+ shouldDeny = durationMs > mMaxDurationMs || mDroppedUids.contains(uid);
+ }
+
+ if (!shouldDeny) {
+ // Nothing to do
+ return false;
+ }
+
+ synchronized (mLock) {
+ if (!mActiveDeniedUids.contains(uid)
+ && mActivityManager.getUidImportance(uid) == IMPORTANCE_FOREGROUND) {
+ // Show UI for the first denial while foreground
+ mUiNotifier.denied(uid);
+
+ if (mActiveDeniedUids.isEmpty()) {
+ // Start a uid listener if this is the first uid triggering a denial UI
+ mActivityManager.addOnUidImportanceListener(this, IMPORTANCE_FOREGROUND);
+ }
+ mActiveDeniedUids.add(uid);
+ }
+ }
+ return true;
+ }
+
+ void onTranscodingDropped(int uid) {
+ synchronized (mLock) {
+ mDroppedUids.add(uid);
+ }
+ // Notify about file access, so we might show a denial UI
+ checkFileAccess(uid, 0 /* duration */);
+ }
+ }
+
+ private static final class SessionTiming {
+ // This should be accessed only in foreground thread.
+ private final SparseArray<Long> mSessionStartTimes = new SparseArray<>();
+
+ // Call this only in foreground thread.
+ private long getSessionStartTime(MediaTranscodeManager.TranscodingSession session) {
+ return mSessionStartTimes.get(session.getSessionId());
+ }
+
+ private void logSessionStart(MediaTranscodeManager.TranscodingSession session) {
+ ForegroundThread.getHandler().post(
+ () -> mSessionStartTimes.append(session.getSessionId(),
+ System.currentTimeMillis()));
+ }
+
+ private void logSessionEnd(MediaTranscodeManager.TranscodingSession session) {
+ ForegroundThread.getHandler().post(
+ () -> mSessionStartTimes.remove(session.getSessionId()));
+ }
+ }
+}
diff --git a/src/com/android/providers/media/VolumeCache.java b/src/com/android/providers/media/VolumeCache.java
new file mode 100644
index 0000000..cbcd230
--- /dev/null
+++ b/src/com/android/providers/media/VolumeCache.java
@@ -0,0 +1,203 @@
+/*
+ * 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;
+
+import static com.android.providers.media.util.Logging.TAG;
+
+import android.content.Context;
+import android.net.Uri;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageVolume;
+import android.provider.MediaStore;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.LongSparseArray;
+
+import androidx.annotation.GuardedBy;
+import androidx.annotation.NonNull;
+
+import com.android.providers.media.util.FileUtils;
+import com.android.providers.media.util.UserCache;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * The VolumeCache class keeps track of all the volumes that are available,
+ * as well as their scan paths.
+ */
+public class VolumeCache {
+ private final Context mContext;
+
+ private final Object mLock = new Object();
+
+ private final UserManager mUserManager;
+ private final UserCache mUserCache;
+
+ @GuardedBy("mLock")
+ private final ArrayList<MediaVolume> mExternalVolumes = new ArrayList<>();
+
+ @GuardedBy("mLock")
+ private final Map<MediaVolume, Collection<File>> mCachedVolumeScanPaths = new ArrayMap<>();
+
+ @GuardedBy("mLock")
+ private Collection<File> mCachedInternalScanPaths;
+
+ public VolumeCache(Context context, UserCache userCache) {
+ mContext = context;
+ mUserManager = context.getSystemService(UserManager.class);
+ mUserCache = userCache;
+ }
+
+ public @NonNull List<MediaVolume> getExternalVolumes() {
+ synchronized(mLock) {
+ return new ArrayList<>(mExternalVolumes);
+ }
+ }
+
+ public @NonNull Set<String> getExternalVolumeNames() {
+ synchronized (mLock) {
+ ArraySet<String> volNames = new ArraySet<String>();
+ for (MediaVolume vol : mExternalVolumes) {
+ volNames.add(vol.getName());
+ }
+ return volNames;
+ }
+ }
+
+ public @NonNull MediaVolume findVolume(@NonNull String volumeName, @NonNull UserHandle user)
+ throws FileNotFoundException {
+ synchronized (mLock) {
+ for (MediaVolume vol : mExternalVolumes) {
+ if (vol.getName().equals(volumeName) && vol.isVisibleToUser(user)) {
+ return vol;
+ }
+ }
+ }
+
+ throw new FileNotFoundException("Couldn't find volume with name " + volumeName);
+ }
+
+ public @NonNull File getVolumePath(@NonNull String volumeName, @NonNull UserHandle user)
+ throws FileNotFoundException {
+ synchronized (mLock) {
+ try {
+ MediaVolume volume = findVolume(volumeName, user);
+ return volume.getPath();
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "getVolumePath for unknown volume: " + volumeName);
+ // Try again by using FileUtils below
+ }
+
+ final Context userContext = mUserCache.getContextForUser(user);
+ return FileUtils.getVolumePath(userContext, volumeName);
+ }
+ }
+
+ public @NonNull Collection<File> getVolumeScanPaths(@NonNull String volumeName,
+ @NonNull UserHandle user) throws FileNotFoundException {
+ synchronized (mLock) {
+ if (MediaStore.VOLUME_INTERNAL.equals(volumeName)) {
+ // Internal is shared by all users
+ return mCachedInternalScanPaths;
+ }
+ try {
+ MediaVolume volume = findVolume(volumeName, user);
+ if (mCachedVolumeScanPaths.containsKey(volume)) {
+ return mCachedVolumeScanPaths.get(volume);
+ }
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "Didn't find cached volume scan paths for " + volumeName);
+ }
+
+ // Nothing found above; let's ask directly
+ final Context userContext = mUserCache.getContextForUser(user);
+ final Collection<File> res = FileUtils.getVolumeScanPaths(userContext, volumeName);
+
+ return res;
+ }
+ }
+
+ public @NonNull MediaVolume findVolumeForFile(@NonNull File file) throws FileNotFoundException {
+ synchronized (mLock) {
+ for (MediaVolume volume : mExternalVolumes) {
+ if (FileUtils.contains(volume.getPath(), file)) {
+ return volume;
+ }
+ }
+ }
+
+ Log.w(TAG, "Didn't find any volume for getVolume(" + file.getPath() + ")");
+ // Nothing found above; let's ask directly
+ final StorageManager sm = mContext.getSystemService(StorageManager.class);
+ final StorageVolume volume = sm.getStorageVolume(file);
+ if (volume == null) {
+ throw new FileNotFoundException("Missing volume for " + file);
+ }
+
+ return MediaVolume.fromStorageVolume(volume);
+ }
+
+ public @NonNull String getVolumeId(@NonNull File file) throws FileNotFoundException {
+ MediaVolume volume = findVolumeForFile(file);
+
+ return volume.getId();
+ }
+
+ @GuardedBy("mLock")
+ private void updateExternalVolumesForUserLocked(Context userContext) {
+ final StorageManager sm = userContext.getSystemService(StorageManager.class);
+ for (String volumeName : MediaStore.getExternalVolumeNames(userContext)) {
+ try {
+ final Uri uri = MediaStore.Files.getContentUri(volumeName);
+ final StorageVolume storageVolume = sm.getStorageVolume(uri);
+ MediaVolume volume = MediaVolume.fromStorageVolume(storageVolume);
+ mExternalVolumes.add(volume);
+ mCachedVolumeScanPaths.put(volume, FileUtils.getVolumeScanPaths(userContext,
+ volume.getName()));
+ } catch (IllegalStateException | FileNotFoundException e) {
+ Log.wtf(TAG, "Failed to update volume " + volumeName, e);
+ }
+ }
+ }
+
+ public void update() {
+ synchronized (mLock) {
+ mCachedVolumeScanPaths.clear();
+ try {
+ mCachedInternalScanPaths = FileUtils.getVolumeScanPaths(mContext,
+ MediaStore.VOLUME_INTERNAL);
+ } catch (FileNotFoundException e) {
+ Log.wtf(TAG, "Failed to update volume " + MediaStore.VOLUME_INTERNAL,e );
+ }
+ mExternalVolumes.clear();
+ List<UserHandle> users = mUserCache.updateAndGetUsers();
+ for (UserHandle user : users) {
+ Context userContext = mUserCache.getContextForUser(user);
+ updateExternalVolumesForUserLocked(userContext);
+ }
+ }
+ }
+}
diff --git a/src/com/android/providers/media/fuse/ExternalStorageServiceImpl.java b/src/com/android/providers/media/fuse/ExternalStorageServiceImpl.java
index 0c1cb94..1f8f3cd 100644
--- a/src/com/android/providers/media/fuse/ExternalStorageServiceImpl.java
+++ b/src/com/android/providers/media/fuse/ExternalStorageServiceImpl.java
@@ -18,6 +18,7 @@
import static com.android.providers.media.scan.MediaScanner.REASON_MOUNTED;
+import android.annotation.BytesLong;
import android.content.ContentProviderClient;
import android.os.Environment;
import android.os.OperationCanceledException;
@@ -32,11 +33,14 @@
import com.android.providers.media.MediaProvider;
import com.android.providers.media.MediaService;
+import com.android.providers.media.MediaVolume;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
+import java.util.Objects;
+import java.util.UUID;
/**
* Handles filesystem I/O from other apps.
@@ -48,9 +52,14 @@
private static final Map<String, FuseDaemon> sFuseDaemons = new HashMap<>();
@Override
- public void onStartSession(String sessionId, /* @SessionFlag */ int flag,
+ public void onStartSession(@NonNull String sessionId, /* @SessionFlag */ int flag,
@NonNull ParcelFileDescriptor deviceFd, @NonNull File upperFileSystemPath,
@NonNull File lowerFileSystemPath) {
+ Objects.requireNonNull(sessionId);
+ Objects.requireNonNull(deviceFd);
+ Objects.requireNonNull(upperFileSystemPath);
+ Objects.requireNonNull(lowerFileSystemPath);
+
MediaProvider mediaProvider = getMediaProvider();
synchronized (sLock) {
@@ -70,22 +79,25 @@
}
@Override
- public void onVolumeStateChanged(StorageVolume vol) throws IOException {
+ public void onVolumeStateChanged(@NonNull StorageVolume vol) throws IOException {
+ Objects.requireNonNull(vol);
+
MediaProvider mediaProvider = getMediaProvider();
- String volumeName = vol.getMediaStoreVolumeName();
switch(vol.getState()) {
case Environment.MEDIA_MOUNTED:
- mediaProvider.attachVolume(volumeName, /* validate */ false);
+ MediaVolume volume = MediaVolume.fromStorageVolume(vol);
+ mediaProvider.attachVolume(volume, /* validate */ false);
+ MediaService.queueVolumeScan(mediaProvider.getContext(), volume, REASON_MOUNTED);
break;
case Environment.MEDIA_UNMOUNTED:
case Environment.MEDIA_EJECTING:
case Environment.MEDIA_REMOVED:
case Environment.MEDIA_BAD_REMOVAL:
- mediaProvider.detachVolume(volumeName);
+ mediaProvider.detachVolume(MediaVolume.fromStorageVolume(vol));
break;
default:
- Log.i(TAG, "Ignoring volume state for vol:" + volumeName
+ Log.i(TAG, "Ignoring volume state for vol:" + vol.getMediaStoreVolumeName()
+ ". State: " + vol.getState());
}
// Check for invalidation of cached volumes
@@ -93,7 +105,9 @@
}
@Override
- public void onEndSession(String sessionId) {
+ public void onEndSession(@NonNull String sessionId) {
+ Objects.requireNonNull(sessionId);
+
FuseDaemon daemon = onExitSession(sessionId);
if (daemon == null) {
@@ -108,7 +122,24 @@
}
}
- public FuseDaemon onExitSession(String sessionId) {
+ @Override
+ public void onFreeCache(@NonNull UUID volumeUuid, @BytesLong long bytes) throws IOException {
+ Objects.requireNonNull(volumeUuid);
+
+ Log.i(TAG, "Free cache requested for " + bytes + " bytes");
+ getMediaProvider().freeCache(bytes);
+ }
+
+ @Override
+ public void onAnrDelayStarted(@NonNull String packageName, int uid, int tid, int reason) {
+ Objects.requireNonNull(packageName);
+
+ getMediaProvider().onAnrDelayStarted(packageName, uid, tid, reason);
+ }
+
+ public FuseDaemon onExitSession(@NonNull String sessionId) {
+ Objects.requireNonNull(sessionId);
+
Log.i(TAG, "Exiting session for id: " + sessionId);
synchronized (sLock) {
return sFuseDaemons.remove(sessionId);
diff --git a/src/com/android/providers/media/fuse/FuseDaemon.java b/src/com/android/providers/media/fuse/FuseDaemon.java
index 9a433c9..1175249 100644
--- a/src/com/android/providers/media/fuse/FuseDaemon.java
+++ b/src/com/android/providers/media/fuse/FuseDaemon.java
@@ -24,6 +24,8 @@
import com.android.internal.annotations.GuardedBy;
import com.android.providers.media.MediaProvider;
+import java.io.File;
+import java.io.IOException;
import java.util.Objects;
/**
@@ -82,6 +84,20 @@
// Wait for native_start
waitForStart();
+
+ // Initialize device id
+ initializeDeviceId();
+ }
+
+ private void initializeDeviceId() {
+ synchronized (mLock) {
+ if (mPtr == 0) {
+ Log.e(TAG, "initializeDeviceId failed, FUSE daemon unavailable");
+ return;
+ }
+ String path = mMediaProvider.getFuseFile(new File(mPath)).getAbsolutePath();
+ native_initialize_device_id(mPtr, path);
+ }
}
private void waitForStart() {
@@ -151,6 +167,16 @@
}
}
+ public String getOriginalMediaFormatFilePath(ParcelFileDescriptor fileDescriptor)
+ throws IOException {
+ synchronized (mLock) {
+ if (mPtr == 0) {
+ throw new IOException("FUSE daemon unavailable");
+ }
+ return native_get_original_media_format_file_path(mPtr, fileDescriptor.getFd());
+ }
+ }
+
private native long native_new(MediaProvider mediaProvider);
// Takes ownership of the passed in file descriptor!
@@ -161,5 +187,7 @@
int fd);
private native void native_invalidate_fuse_dentry_cache(long daemon, String path);
private native boolean native_is_started(long daemon);
+ private native String native_get_original_media_format_file_path(long daemon, int fd);
+ private native void native_initialize_device_id(long daemon, String path);
public static native boolean native_is_fuse_thread();
}
diff --git a/src/com/android/providers/media/metrics/PulledMetrics.java b/src/com/android/providers/media/metrics/PulledMetrics.java
new file mode 100644
index 0000000..f9c5fac
--- /dev/null
+++ b/src/com/android/providers/media/metrics/PulledMetrics.java
@@ -0,0 +1,141 @@
+/*
+ * 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.metrics;
+
+import static com.android.providers.media.MediaProviderStatsLog.GENERAL_EXTERNAL_STORAGE_ACCESS_STATS;
+import static com.android.providers.media.MediaProviderStatsLog.TRANSCODING_DATA;
+
+import android.app.StatsManager;
+import android.content.Context;
+import android.util.Log;
+import android.util.StatsEvent;
+
+import androidx.annotation.NonNull;
+
+import com.android.providers.media.fuse.FuseDaemon;
+import com.android.providers.media.util.BackgroundThread;
+
+import java.util.List;
+
+/** A class to initialise and log metrics pulled by statsd. */
+public class PulledMetrics {
+ private static final String TAG = "PulledMetrics";
+
+ private static final StatsPullCallbackHandler STATS_PULL_CALLBACK_HANDLER =
+ new StatsPullCallbackHandler();
+
+ private static final StorageAccessMetrics storageAccessMetrics = new StorageAccessMetrics();
+
+ private static boolean isInitialized = false;
+
+ public static void initialize(Context context) {
+ if (isInitialized) {
+ return;
+ }
+
+ final StatsManager statsManager = context.getSystemService(StatsManager.class);
+ if (statsManager == null) {
+ Log.e(TAG, "Error retrieving StatsManager. Cannot initialize PulledMetrics.");
+ } else {
+ Log.d(TAG, "Registering callback with StatsManager");
+
+ try {
+ // use the same callback handler for registering for all the tags.
+ statsManager.setPullAtomCallback(TRANSCODING_DATA, null /* metadata */,
+ BackgroundThread.getExecutor(),
+ STATS_PULL_CALLBACK_HANDLER);
+ statsManager.setPullAtomCallback(
+ GENERAL_EXTERNAL_STORAGE_ACCESS_STATS,
+ /*metadata*/null,
+ BackgroundThread.getExecutor(),
+ STATS_PULL_CALLBACK_HANDLER);
+ isInitialized = true;
+ } catch (NullPointerException e) {
+ Log.w(TAG, "Pulled metrics not supported. Could not register.", e);
+ }
+ }
+ }
+
+ // Storage Access Metrics log functions
+
+ /**
+ * Logs the mime type that was accessed by the given {@code uid}.
+ * Does nothing if the stats puller is not initialized.
+ */
+ public static void logMimeTypeAccess(int uid, @NonNull String mimeType) {
+ if (!isInitialized) {
+ return;
+ }
+
+ storageAccessMetrics.logMimeType(uid, mimeType);
+ }
+
+ /**
+ * Logs the storage access and attributes it to the given {@code uid}.
+ *
+ * <p>Should only be called from a FUSE thread.
+ */
+ public static void logFileAccessViaFuse(int uid, @NonNull String file) {
+ if (!isInitialized) {
+ return;
+ }
+
+ storageAccessMetrics.logAccessViaFuse(uid, file);
+ }
+
+ /**
+ * Logs the storage access and attributes it to the given {@code uid}.
+ *
+ * <p>This is a no-op if it's called on a FUSE thread.
+ */
+ public static void logVolumeAccessViaMediaProvider(int uid, @NonNull String volumeName) {
+ if (!isInitialized) {
+ return;
+ }
+
+ // We don't log if it's a FUSE thread because logAccessViaFuse should handle that.
+ if (FuseDaemon.native_is_fuse_thread()) {
+ return;
+ }
+ storageAccessMetrics.logAccessViaMediaProvider(uid, volumeName);
+ }
+
+ private static class StatsPullCallbackHandler implements StatsManager.StatsPullAtomCallback {
+ @Override
+ public int onPullAtom(int atomTag, List<StatsEvent> data) {
+ // handle the tags appropriately.
+ List<StatsEvent> events = pullEvents(atomTag);
+ if (events == null) {
+ return StatsManager.PULL_SKIP;
+ }
+
+ data.addAll(events);
+ return StatsManager.PULL_SUCCESS;
+ }
+
+ private List<StatsEvent> pullEvents(int atomTag) {
+ switch (atomTag) {
+ case TRANSCODING_DATA:
+ return TranscodeMetrics.pullStatsEvents();
+ case GENERAL_EXTERNAL_STORAGE_ACCESS_STATS:
+ return storageAccessMetrics.pullStatsEvents();
+ default:
+ return null;
+ }
+ }
+ }
+}
diff --git a/src/com/android/providers/media/metrics/StatsdPuller.java b/src/com/android/providers/media/metrics/StatsdPuller.java
deleted file mode 100644
index 606d058..0000000
--- a/src/com/android/providers/media/metrics/StatsdPuller.java
+++ /dev/null
@@ -1,64 +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.metrics;
-
-import android.app.StatsManager;
-import android.content.Context;
-import android.os.Build;
-import android.util.Log;
-import android.util.StatsEvent;
-
-import java.util.List;
-
-/**
- * A "static" class providing the boilerplate for handling the pulling of metrics by statsd.
- * All individuals using this should accumulate their metrics per their policies.
- */
-public class StatsdPuller {
- private static final String TAG = "StatsdPuller";
-
- private static final StatsPullCallbackHandler STATS_PULL_CALLBACK_HANDLER =
- new StatsPullCallbackHandler();
-
- private static boolean isInitialized = false;
-
- public static void initialize(Context context) {
- if (isInitialized) {
- return;
- }
-
- final StatsManager statsManager = context.getSystemService(StatsManager.class);
- if (statsManager == null) {
- Log.e(TAG, "Error retrieving StatsManager. Cannot initialize StatsdPuller.");
- } else {
- // use the same callback handler for registering for all the tags.
- isInitialized = true;
- }
- }
-
- public static boolean isInitialized() {
- return isInitialized;
- }
-
- private static class StatsPullCallbackHandler implements StatsManager.StatsPullAtomCallback {
- @Override
- public int onPullAtom(int atomTag, List<StatsEvent> data) {
- // handle the tags appropriately.
- return StatsManager.PULL_SUCCESS;
- }
- }
-}
diff --git a/src/com/android/providers/media/metrics/StorageAccessMetrics.java b/src/com/android/providers/media/metrics/StorageAccessMetrics.java
new file mode 100644
index 0000000..ce54e3f
--- /dev/null
+++ b/src/com/android/providers/media/metrics/StorageAccessMetrics.java
@@ -0,0 +1,279 @@
+/*
+ * 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.metrics;
+
+import static com.android.providers.media.MediaProviderStatsLog.GENERAL_EXTERNAL_STORAGE_ACCESS_STATS;
+
+import static java.util.stream.Collectors.toList;
+
+import android.os.Process;
+import android.os.SystemClock;
+import android.provider.MediaStore;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.SparseArray;
+import android.util.StatsEvent;
+import android.util.proto.ProtoOutputStream;
+
+import androidx.annotation.GuardedBy;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.providers.media.MediaProviderStatsLog;
+import com.android.providers.media.util.FileUtils;
+import com.android.providers.media.util.MimeUtils;
+
+import com.google.common.annotations.VisibleForTesting;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Metrics for {@link MediaProviderStatsLog#GENERAL_EXTERNAL_STORAGE_ACCESS_STATS}. This class
+ * gathers stats separately for each UID that accesses external storage.
+ */
+class StorageAccessMetrics {
+
+ private static final String TAG = "StorageAccessMetrics";
+
+ @VisibleForTesting
+ static final int UID_SAMPLES_COUNT_LIMIT = 50;
+
+ private final int mMyUid = Process.myUid();
+
+ @GuardedBy("mLock")
+ private final SparseArray<PackageStorageAccessStats> mAccessStatsPerPackage =
+ new SparseArray<>();
+ @GuardedBy("mLock")
+ private long mStartTimeMillis = SystemClock.uptimeMillis();
+
+ private final Object mLock = new Object();
+
+
+ /**
+ * Logs the mime type that was accessed by the given {@code uid}.
+ */
+ void logMimeType(int uid, @NonNull String mimeType) {
+ if (mimeType == null) {
+ Log.w(TAG, "Attempted to log null mime type access");
+ return;
+ }
+
+ synchronized (mLock) {
+ getOrGeneratePackageStatsObjectLocked(uid).mMimeTypes.add(mimeType);
+ }
+ }
+
+ /**
+ * Logs the storage access and attributes it to the given {@code uid}.
+ *
+ * <p>Should only be called from a FUSE thread.
+ */
+ void logAccessViaFuse(int uid, @NonNull String file) {
+ // We don't log the access if it's MediaProvider accessing.
+ if (mMyUid == uid) {
+ return;
+ }
+
+ incrementFilePathAccesses(uid);
+ final String volumeName = MediaStore.getVolumeName(
+ FileUtils.getContentUriForPath(file));
+ logGeneralExternalStorageAccess(uid, volumeName);
+ logMimeTypeFromFile(uid, file);
+ }
+
+
+ /**
+ * Logs the storage access and attributes it to the given {@code uid}.
+ */
+ void logAccessViaMediaProvider(int uid, @NonNull String volumeName) {
+ // We also don't log the access if it's MediaProvider accessing.
+ if (mMyUid == uid) {
+ return;
+ }
+
+ logGeneralExternalStorageAccess(uid, volumeName);
+ }
+
+ /**
+ * Use this to log whenever a package accesses external storage via ContentResolver or FUSE.
+ * The given volume name helps us determine whether this was an access on primary or secondary
+ * storage.
+ */
+ private void logGeneralExternalStorageAccess(int uid, @NonNull String volumeName) {
+ switch (volumeName) {
+ case MediaStore.VOLUME_EXTERNAL:
+ case MediaStore.VOLUME_EXTERNAL_PRIMARY:
+ incrementTotalAccesses(uid);
+ break;
+ case MediaStore.VOLUME_INTERNAL:
+ case MediaStore.VOLUME_DEMO:
+ case MediaStore.MEDIA_SCANNER_VOLUME:
+ break;
+ default:
+ // Secondary external storage
+ incrementTotalAccesses(uid);
+ incrementSecondaryStorageAccesses(uid);
+ }
+ }
+
+ /**
+ * Logs that the mime type of the given {@param file} was accessed by the given {@param uid}.
+ */
+ private void logMimeTypeFromFile(int uid, @Nullable String file) {
+ logMimeType(uid, MimeUtils.resolveMimeType(new File(file)));
+ }
+
+ private void incrementTotalAccesses(int uid) {
+ synchronized (mLock) {
+ getOrGeneratePackageStatsObjectLocked(uid).mTotalAccesses += 1;
+ }
+ }
+
+ private void incrementFilePathAccesses(int uid) {
+ synchronized (mLock) {
+ getOrGeneratePackageStatsObjectLocked(uid).mFilePathAccesses += 1;
+ }
+ }
+
+ private void incrementSecondaryStorageAccesses(int uid) {
+ synchronized (mLock) {
+ getOrGeneratePackageStatsObjectLocked(uid).mSecondaryStorageAccesses += 1;
+ }
+ }
+
+ @GuardedBy("mLock")
+ private PackageStorageAccessStats getOrGeneratePackageStatsObjectLocked(int uid) {
+ PackageStorageAccessStats stats = mAccessStatsPerPackage.get(uid);
+ if (stats == null) {
+ stats = new PackageStorageAccessStats(uid);
+ mAccessStatsPerPackage.put(uid, stats);
+ }
+ return stats;
+ }
+
+ /**
+ * Returns the list of {@link StatsEvent} since latest reset, for a random subset of tracked
+ * uids if there are more than {@link #UID_SAMPLES_COUNT_LIMIT} in total. Returns {@code null}
+ * when the time since reset is non-positive.
+ */
+ @Nullable
+ List<StatsEvent> pullStatsEvents() {
+ synchronized (mLock) {
+ final long timeInterval = SystemClock.uptimeMillis() - mStartTimeMillis;
+ List<PackageStorageAccessStats> stats = getSampleStats();
+ resetStats();
+ return stats
+ .stream()
+ .map(s -> s.toNormalizedStats(timeInterval).toStatsEvent())
+ .collect(toList());
+ }
+ }
+
+ @VisibleForTesting
+ List<PackageStorageAccessStats> getSampleStats() {
+ synchronized (mLock) {
+ List<PackageStorageAccessStats> result = new ArrayList<>();
+
+ List<Integer> sampledUids = new ArrayList<>();
+ for (int i = 0; i < mAccessStatsPerPackage.size(); i++) {
+ sampledUids.add(mAccessStatsPerPackage.keyAt(i));
+ }
+
+ if (sampledUids.size() > UID_SAMPLES_COUNT_LIMIT) {
+ Collections.shuffle(sampledUids);
+ sampledUids = sampledUids.subList(0, UID_SAMPLES_COUNT_LIMIT);
+ }
+ for (Integer uid : sampledUids) {
+ PackageStorageAccessStats stats = mAccessStatsPerPackage.get(uid);
+ result.add(stats);
+ }
+
+ return result;
+ }
+ }
+
+ private void resetStats() {
+ synchronized (mLock) {
+ mAccessStatsPerPackage.clear();
+ mStartTimeMillis = SystemClock.uptimeMillis();
+ }
+ }
+
+ @VisibleForTesting
+ static class PackageStorageAccessStats {
+ private final int mUid;
+ int mTotalAccesses = 0;
+ int mFilePathAccesses = 0;
+ int mSecondaryStorageAccesses = 0;
+
+ final ArraySet<String> mMimeTypes = new ArraySet<>();
+
+ PackageStorageAccessStats(int uid) {
+ this.mUid = uid;
+ }
+
+ PackageStorageAccessStats toNormalizedStats(long timeInterval) {
+ this.mTotalAccesses = normalizeAccessesPerDay(mTotalAccesses, timeInterval);
+ this.mFilePathAccesses = normalizeAccessesPerDay(mFilePathAccesses, timeInterval);
+ this.mSecondaryStorageAccesses =
+ normalizeAccessesPerDay(mSecondaryStorageAccesses, timeInterval);
+ return this;
+ }
+
+ StatsEvent toStatsEvent() {
+ return StatsEvent.newBuilder()
+ .setAtomId(GENERAL_EXTERNAL_STORAGE_ACCESS_STATS)
+ .writeInt(mUid)
+ .writeInt(mTotalAccesses)
+ .writeInt(mFilePathAccesses)
+ .writeInt(mSecondaryStorageAccesses)
+ .writeByteArray(getMimeTypesAsProto().getBytes())
+ .build();
+ }
+
+ private ProtoOutputStream getMimeTypesAsProto() {
+ ProtoOutputStream proto = new ProtoOutputStream();
+ for (int i = 0; i < mMimeTypes.size(); i++) {
+ String mime = mMimeTypes.valueAt(i);
+ proto.write(/*fieldId*/ProtoOutputStream.FIELD_TYPE_STRING
+ | ProtoOutputStream.FIELD_COUNT_REPEATED
+ | 1,
+ mime);
+ }
+ return proto;
+ }
+
+ private static int normalizeAccessesPerDay(int value, long interval) {
+ if (interval <= 0) {
+ return -1;
+ }
+
+ double multiplier = Double.valueOf(TimeUnit.DAYS.toMillis(1)) / interval;
+ double normalizedValue = value * multiplier;
+ return Double.valueOf(normalizedValue).intValue();
+ }
+
+ @VisibleForTesting
+ int getUid() {
+ return mUid;
+ }
+ }
+}
diff --git a/src/com/android/providers/media/metrics/TranscodeMetrics.java b/src/com/android/providers/media/metrics/TranscodeMetrics.java
new file mode 100644
index 0000000..ec6a685
--- /dev/null
+++ b/src/com/android/providers/media/metrics/TranscodeMetrics.java
@@ -0,0 +1,179 @@
+/*
+ * 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.metrics;
+
+import static com.android.providers.media.MediaProviderStatsLog.TRANSCODING_DATA;
+
+import android.app.StatsManager;
+import android.util.StatsEvent;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+
+/**
+ * Stores metrics for transcode sessions to be shared with statsd.
+ */
+final class TranscodeMetrics {
+ private static final List<TranscodingStatsData> TRANSCODING_STATS_DATA = new ArrayList<>();
+
+ // PLEASE update these if there's a change in the proto message, per the limit set in
+ // StatsEvent#MAX_PULL_PAYLOAD_SIZE
+ private static final int STATS_DATA_SAMPLE_LIMIT = 300;
+ private static final int STATS_DATA_COUNT_HARD_LIMIT = 500; // for safety
+
+ // Total data save requests we've received for one statsd pull cycle.
+ // This can be greater than TRANSCODING_STATS_DATA.size() since we might not add all the
+ // incoming data because of the hard limit on the size.
+ private static int sTotalStatsDataCount = 0;
+
+ static List<StatsEvent> pullStatsEvents() {
+ synchronized (TRANSCODING_STATS_DATA) {
+ if (TRANSCODING_STATS_DATA.size() > STATS_DATA_SAMPLE_LIMIT) {
+ doRandomSampling();
+ }
+
+ List<StatsEvent> result = getStatsEvents();
+ resetStatsData();
+ return result;
+ }
+ }
+
+ private static List<StatsEvent> getStatsEvents() {
+ synchronized (TRANSCODING_STATS_DATA) {
+ List<StatsEvent> result = new ArrayList<>();
+ StatsEvent event;
+ int dataCountToFill = Math.min(TRANSCODING_STATS_DATA.size(), STATS_DATA_SAMPLE_LIMIT);
+ for (int i = 0; i < dataCountToFill; ++i) {
+ TranscodingStatsData statsData = TRANSCODING_STATS_DATA.get(i);
+ event = StatsEvent.newBuilder().setAtomId(TRANSCODING_DATA)
+ .writeString(statsData.mRequestorPackage)
+ .writeInt(statsData.mAccessType)
+ .writeLong(statsData.mFileSizeBytes)
+ .writeInt(statsData.mTranscodeResult)
+ .writeLong(statsData.mTranscodeDurationMillis)
+ .writeLong(statsData.mFileDurationMillis)
+ .writeLong(statsData.mFrameRate)
+ .writeInt(statsData.mAccessReason).build();
+
+ result.add(event);
+ }
+ return result;
+ }
+ }
+
+ /**
+ * The random samples would get collected in the first {@code STATS_DATA_SAMPLE_LIMIT} positions
+ * inside {@code TRANSCODING_STATS_DATA}
+ */
+ private static void doRandomSampling() {
+ Random random = new Random(System.currentTimeMillis());
+
+ synchronized (TRANSCODING_STATS_DATA) {
+ for (int i = 0; i < STATS_DATA_SAMPLE_LIMIT; ++i) {
+ int randomIndex = random.nextInt(TRANSCODING_STATS_DATA.size() - i /* bound */)
+ + i;
+ Collections.swap(TRANSCODING_STATS_DATA, i, randomIndex);
+ }
+ }
+ }
+
+ @VisibleForTesting
+ static void resetStatsData() {
+ synchronized (TRANSCODING_STATS_DATA) {
+ TRANSCODING_STATS_DATA.clear();
+ sTotalStatsDataCount = 0;
+ }
+ }
+
+ /** Saves the statsd data that'd eventually be shared in the pull callback. */
+ @VisibleForTesting
+ static void saveStatsData(TranscodingStatsData transcodingStatsData) {
+ checkAndLimitStatsDataSizeAfterAddition(transcodingStatsData);
+ }
+
+ private static void checkAndLimitStatsDataSizeAfterAddition(
+ TranscodingStatsData transcodingStatsData) {
+ synchronized (TRANSCODING_STATS_DATA) {
+ ++sTotalStatsDataCount;
+
+ if (TRANSCODING_STATS_DATA.size() < STATS_DATA_COUNT_HARD_LIMIT) {
+ TRANSCODING_STATS_DATA.add(transcodingStatsData);
+ return;
+ }
+
+ // Depending on how much transcoding we are doing, we might end up accumulating a lot of
+ // data by the time statsd comes back with the pull callback.
+ // We don't want to just keep growing our memory usage.
+ // So we simply randomly choose an element to remove with equal likeliness.
+ Random random = new Random(System.currentTimeMillis());
+ int replaceIndex = random.nextInt(sTotalStatsDataCount /* bound */);
+
+ if (replaceIndex < STATS_DATA_COUNT_HARD_LIMIT) {
+ TRANSCODING_STATS_DATA.set(replaceIndex, transcodingStatsData);
+ }
+ }
+ }
+
+ @VisibleForTesting
+ static int getSavedStatsDataCount() {
+ return TRANSCODING_STATS_DATA.size();
+ }
+
+ @VisibleForTesting
+ static int getTotalStatsDataCount() {
+ return sTotalStatsDataCount;
+ }
+
+ @VisibleForTesting
+ static int getStatsDataCountHardLimit() {
+ return STATS_DATA_COUNT_HARD_LIMIT;
+ }
+
+ @VisibleForTesting
+ static int getStatsDataSampleLimit() {
+ return STATS_DATA_SAMPLE_LIMIT;
+ }
+
+ /** This is the data to populate the proto shared to westworld. */
+ static final class TranscodingStatsData {
+ private final String mRequestorPackage;
+ private final short mAccessType;
+ private final long mFileSizeBytes;
+ private final short mTranscodeResult;
+ private final long mTranscodeDurationMillis;
+ private final long mFileDurationMillis;
+ private final long mFrameRate;
+ private final short mAccessReason;
+
+ TranscodingStatsData(String requestorPackage, int accessType, long fileSizeBytes,
+ int transcodeResult, long transcodeDurationMillis,
+ long videoDurationMillis, long frameRate, short transcodeReason) {
+ mRequestorPackage = requestorPackage;
+ mAccessType = (short) accessType;
+ mFileSizeBytes = fileSizeBytes;
+ mTranscodeResult = (short) transcodeResult;
+ mTranscodeDurationMillis = transcodeDurationMillis;
+ mFileDurationMillis = videoDurationMillis;
+ mFrameRate = frameRate;
+ mAccessReason = transcodeReason;
+ }
+ }
+}
diff --git a/src/com/android/providers/media/photopicker/PhotoPickerActivity.java b/src/com/android/providers/media/photopicker/PhotoPickerActivity.java
new file mode 100644
index 0000000..66182bc
--- /dev/null
+++ b/src/com/android/providers/media/photopicker/PhotoPickerActivity.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2020 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;
+
+import android.app.Activity;
+import android.content.ClipData;
+import android.content.ClipDescription;
+import android.content.ContentUris;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.MediaStore;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.ListView;
+
+import com.android.providers.media.R;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Photo Picker allows users to choose one or more photos and/or videos to share with an app. The
+ * app does not get access to all photos/videos.
+ */
+public class PhotoPickerActivity extends Activity {
+
+ public static final String TAG = "PhotoPickerActivity";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // TODO(b/168001592) Change layout to show photos & options.
+ setContentView(R.layout.photo_picker);
+ Button button = findViewById(R.id.button);
+ button.setOnClickListener(v -> respondEmpty());
+
+ // TODO(b/168001592) Handle multiple selection option.
+
+ // TODO(b/168001592) Filter using given mime type.
+
+ // TODO(b/168001592) Show a photo grid instead of ListView.
+ ListView photosList = findViewById(R.id.names_list);
+ ArrayAdapter<PhotoEntry> photosAdapter = new ArrayAdapter<>(
+ this, android.R.layout.simple_list_item_1);
+ photosList.setAdapter(photosAdapter);
+ // Clicking an item in the list returns its URI for now.
+ photosList.setOnItemClickListener((parent, view, position, id) -> {
+ respondPhoto(photosAdapter.getItem(position));
+ });
+
+ // Show the list of photo names for now.
+ ImmutableList.Builder<PhotoEntry> imageRowsBuilder = ImmutableList.builder();
+ String[] projection = new String[] {
+ MediaStore.MediaColumns._ID,
+ MediaStore.MediaColumns.DISPLAY_NAME
+ };
+ // TODO(b/168001592) call query() from worker thread.
+ Cursor cursor = getApplicationContext().getContentResolver().query(
+ MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+ projection, null, null);
+ int idColumn = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID);
+ int nameColumn = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME);
+ // TODO(b/168001592) Use better image loading (e.g. use paging, glide).
+ while (cursor.moveToNext()) {
+ imageRowsBuilder.add(
+ new PhotoEntry(cursor.getLong(idColumn), cursor.getString(nameColumn)));
+ }
+ photosAdapter.addAll(imageRowsBuilder.build());
+ }
+
+ private void respondPhoto(PhotoEntry photoEntry) {
+ Uri contentUri = ContentUris.withAppendedId(
+ MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+ photoEntry.id);
+
+ Intent response = new Intent();
+ // TODO(b/168001592) Confirm if this flag is enough to grant the access we want.
+ response.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+ // TODO(b/168001592) Use a better label and accurate mime types.
+ if (getIntent().getBooleanExtra(Intent.EXTRA_ALLOW_MULTIPLE, false)) {
+ ClipDescription clipDescription = new ClipDescription(
+ "Photo Picker ClipData",
+ new String[]{"image/*", "video/*"});
+ ClipData clipData = new ClipData(clipDescription, new ClipData.Item(contentUri));
+ response.setClipData(clipData);
+ } else {
+ response.setData(contentUri);
+ }
+
+ setResult(Activity.RESULT_OK, response);
+ finish();
+ }
+
+
+ private void respondEmpty() {
+ setResult(Activity.RESULT_OK);
+ finish();
+ }
+
+ private static class PhotoEntry {
+ private long id;
+ private String name;
+
+ PhotoEntry(long id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+ }
+}
diff --git a/src/com/android/providers/media/scan/LegacyMediaScanner.java b/src/com/android/providers/media/scan/LegacyMediaScanner.java
index 0a53a0d..d8d3bed 100644
--- a/src/com/android/providers/media/scan/LegacyMediaScanner.java
+++ b/src/com/android/providers/media/scan/LegacyMediaScanner.java
@@ -21,6 +21,8 @@
import androidx.annotation.Nullable;
+import com.android.providers.media.MediaVolume;
+
import java.io.File;
@Deprecated
@@ -52,7 +54,7 @@
}
@Override
- public void onDetachVolume(String volumeName) {
+ public void onDetachVolume(MediaVolume volume) {
throw new UnsupportedOperationException();
}
diff --git a/src/com/android/providers/media/scan/MediaScanner.java b/src/com/android/providers/media/scan/MediaScanner.java
index 1306873..45d2a24 100644
--- a/src/com/android/providers/media/scan/MediaScanner.java
+++ b/src/com/android/providers/media/scan/MediaScanner.java
@@ -26,6 +26,8 @@
import androidx.annotation.Nullable;
+import com.android.providers.media.MediaVolume;
+
import java.io.File;
public interface MediaScanner {
@@ -38,7 +40,7 @@
public void scanDirectory(File file, int reason);
public Uri scanFile(File file, int reason);
public Uri scanFile(File file, int reason, @Nullable String ownerPackage);
- public void onDetachVolume(String volumeName);
+ public void onDetachVolume(MediaVolume volume);
public void onIdleScanStopped();
public void onDirectoryDirty(File file);
}
diff --git a/src/com/android/providers/media/scan/ModernMediaScanner.java b/src/com/android/providers/media/scan/ModernMediaScanner.java
index 334f84f..8927bfa 100644
--- a/src/com/android/providers/media/scan/ModernMediaScanner.java
+++ b/src/com/android/providers/media/scan/ModernMediaScanner.java
@@ -37,6 +37,7 @@
import static android.media.MediaMetadataRetriever.METADATA_KEY_MIMETYPE;
import static android.media.MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS;
import static android.media.MediaMetadataRetriever.METADATA_KEY_TITLE;
+import static android.media.MediaMetadataRetriever.METADATA_KEY_VIDEO_CODEC_MIME_TYPE;
import static android.media.MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT;
import static android.media.MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION;
import static android.media.MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH;
@@ -91,11 +92,12 @@
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import com.android.modules.utils.build.SdkLevel;
+import com.android.providers.media.MediaVolume;
import com.android.providers.media.util.DatabaseUtils;
import com.android.providers.media.util.ExifUtils;
import com.android.providers.media.util.FileUtils;
import com.android.providers.media.util.IsoInterface;
-import com.android.providers.media.util.Logging;
import com.android.providers.media.util.LongArray;
import com.android.providers.media.util.Metrics;
import com.android.providers.media.util.MimeUtils;
@@ -174,10 +176,12 @@
static final int MAX_EXCLUDE_DIRS = 450;
private static final Pattern PATTERN_VISIBLE = Pattern.compile(
- "(?i)^/storage/[^/]+(?:/[0-9]+)?(?:/Android/sandbox/([^/]+))?$");
+ "(?i)^/storage/[^/]+(?:/[0-9]+)?$");
private static final Pattern PATTERN_INVISIBLE = Pattern.compile(
- "(?i)^/storage/[^/]+(?:/[0-9]+)?(?:/Android/sandbox/([^/]+))?/" +
- "(?:(?:Android/(?:data|obb)$)|(?:(?:Movies|Music|Pictures)/.thumbnails$))");
+ "(?i)^/storage/[^/]+(?:/[0-9]+)?/"
+ + "(?:(?:Android/(?:data|obb|sandbox)$)|"
+ + "(?:\\.transforms$)|"
+ + "(?:(?:Movies|Music|Pictures)/.thumbnails$))");
private static final Pattern PATTERN_YEAR = Pattern.compile("([1-9][0-9][0-9][0-9])");
@@ -267,10 +271,10 @@
}
@Override
- public void onDetachVolume(String volumeName) {
+ public void onDetachVolume(MediaVolume volume) {
synchronized (mActiveScans) {
for (Scan scan : mActiveScans) {
- if (volumeName.equals(scan.mVolumeName)) {
+ if (volume.equals(scan.mVolume)) {
scan.mSignal.cancel();
}
}
@@ -319,6 +323,7 @@
private final File mRoot;
private final int mReason;
+ private final MediaVolume mVolume;
private final String mVolumeName;
private final Uri mFilesUri;
private final CancellationSignal mSignal;
@@ -361,7 +366,13 @@
mRoot = root;
mReason = reason;
- mVolumeName = FileUtils.getVolumeName(mContext, root);
+
+ if (FileUtils.contains(Environment.getStorageDirectory(), root)) {
+ mVolume = MediaVolume.fromStorageVolume(FileUtils.getStorageVolume(mContext, root));
+ } else {
+ mVolume = MediaVolume.fromInternal();
+ }
+ mVolumeName = mVolume.getName();
mFilesUri = MediaStore.Files.getContentUri(mVolumeName);
mSignal = new CancellationSignal();
@@ -1213,6 +1224,11 @@
sAudioTypes.put(Environment.DIRECTORY_PODCASTS, AudioColumns.IS_PODCAST);
sAudioTypes.put(Environment.DIRECTORY_AUDIOBOOKS, AudioColumns.IS_AUDIOBOOK);
sAudioTypes.put(Environment.DIRECTORY_MUSIC, AudioColumns.IS_MUSIC);
+ if (SdkLevel.isAtLeastS()) {
+ sAudioTypes.put(Environment.DIRECTORY_RECORDINGS, AudioColumns.IS_RECORDING);
+ } else {
+ sAudioTypes.put(FileUtils.DIRECTORY_RECORDINGS, AudioColumns.IS_RECORDING);
+ }
}
private static @NonNull ContentProviderOperation.Builder scanItemAudio(long existingId,
@@ -1301,6 +1317,7 @@
op.withValue(VideoColumns.COLOR_STANDARD, null);
op.withValue(VideoColumns.COLOR_TRANSFER, null);
op.withValue(VideoColumns.COLOR_RANGE, null);
+ op.withValue(FileColumns._VIDEO_CODEC_TYPE, null);
try (FileInputStream is = new FileInputStream(file)) {
try (MediaMetadataRetriever mmr = new MediaMetadataRetriever()) {
@@ -1323,6 +1340,8 @@
parseOptional(mmr.extractMetadata(METADATA_KEY_COLOR_TRANSFER)));
withOptionalValue(op, VideoColumns.COLOR_RANGE,
parseOptional(mmr.extractMetadata(METADATA_KEY_COLOR_RANGE)));
+ withOptionalValue(op, FileColumns._VIDEO_CODEC_TYPE,
+ parseOptional(mmr.extractMetadata(METADATA_KEY_VIDEO_CODEC_MIME_TYPE)));
}
// Also hunt around for XMP metadata
diff --git a/src/com/android/providers/media/scan/NullMediaScanner.java b/src/com/android/providers/media/scan/NullMediaScanner.java
index 3f84109..7a1a396 100644
--- a/src/com/android/providers/media/scan/NullMediaScanner.java
+++ b/src/com/android/providers/media/scan/NullMediaScanner.java
@@ -23,6 +23,8 @@
import androidx.annotation.Nullable;
+import com.android.providers.media.MediaVolume;
+
import java.io.File;
/**
@@ -61,7 +63,7 @@
}
@Override
- public void onDetachVolume(String volumeName) {
+ public void onDetachVolume(MediaVolume volume) {
// Ignored
}
diff --git a/src/com/android/providers/media/util/FileUtils.java b/src/com/android/providers/media/util/FileUtils.java
index 1b1ee49..8e99cbc 100644
--- a/src/com/android/providers/media/util/FileUtils.java
+++ b/src/com/android/providers/media/util/FileUtils.java
@@ -45,9 +45,11 @@
import android.content.ClipDescription;
import android.content.ContentValues;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.os.storage.StorageVolume;
import android.provider.MediaStore;
@@ -64,6 +66,8 @@
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import com.android.modules.utils.build.SdkLevel;
+
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
@@ -857,16 +861,39 @@
}
/**
+ * Return StorageVolume corresponding to the file on Path
+ */
+ public static @NonNull StorageVolume getStorageVolume(@NonNull Context context,
+ @NonNull File path) throws FileNotFoundException {
+ int userId = extractUserId(path.getPath());
+ Context userContext = context;
+ if (userId >= 0 && (context.getUser().getIdentifier() != userId)) {
+ // This volume is for a different user than our context, create a context
+ // for that user to retrieve the correct volume.
+ try {
+ userContext = context.createPackageContextAsUser("system", 0,
+ UserHandle.of(userId));
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new FileNotFoundException("Can't get package context for user " + userId);
+ }
+ }
+
+ StorageVolume volume = userContext.getSystemService(StorageManager.class)
+ .getStorageVolume(path);
+ if (volume == null) {
+ throw new FileNotFoundException("Can't find volume for " + path.getPath());
+ }
+
+ return volume;
+ }
+
+ /**
* Return volume name which hosts the given path.
*/
public static @NonNull String getVolumeName(@NonNull Context context, @NonNull File path)
throws FileNotFoundException {
if (contains(Environment.getStorageDirectory(), path)) {
- StorageVolume volume = context.getSystemService(StorageManager.class)
- .getStorageVolume(path);
- if (volume == null) {
- throw new FileNotFoundException("Can't find volume for " + path.getPath());
- }
+ StorageVolume volume = getStorageVolume(context, path);
return volume.getMediaStoreVolumeName();
} else {
return MediaStore.VOLUME_INTERNAL;
@@ -874,9 +901,9 @@
}
public static final Pattern PATTERN_DOWNLOADS_FILE = Pattern.compile(
- "(?i)^/storage/[^/]+/(?:[0-9]+/)?(?:Android/sandbox/[^/]+/)?Download/.+");
+ "(?i)^/storage/[^/]+/(?:[0-9]+/)?Download/.+");
public static final Pattern PATTERN_DOWNLOADS_DIRECTORY = Pattern.compile(
- "(?i)^/storage/[^/]+/(?:[0-9]+/)?(?:Android/sandbox/[^/]+/)?Download/?");
+ "(?i)^/storage/[^/]+/(?:[0-9]+/)?Download/?");
public static final Pattern PATTERN_EXPIRES_FILE = Pattern.compile(
"(?i)^\\.(pending|trashed)-(\\d+)-([^/]+)$");
public static final Pattern PATTERN_PENDING_FILEPATH_FOR_SQL = Pattern.compile(
@@ -923,7 +950,7 @@
* and which captures the package name as the first group.
*/
public static final Pattern PATTERN_OWNED_PATH = Pattern.compile(
- "(?i)^/storage/[^/]+/(?:[0-9]+/)?Android/(?:data|media|obb|sandbox)/([^/]+)(/?.*)?");
+ "(?i)^/storage/[^/]+/(?:[0-9]+/)?Android/(?:data|media|obb)/([^/]+)(/?.*)?");
/**
* Regex that matches Android/obb or Android/data path.
@@ -937,27 +964,53 @@
public static final Pattern PATTERN_OBB_OR_CHILD_PATH = Pattern.compile(
"(?i)^/storage/[^/]+/(?:[0-9]+/)?Android/(?:obb)(/?.*)");
+ /**
+ * The recordings directory. This is used for R OS. For S OS or later,
+ * we use {@link Environment#DIRECTORY_RECORDINGS} directly.
+ */
+ public static final String DIRECTORY_RECORDINGS = "Recordings";
+
@VisibleForTesting
- public static final String[] DEFAULT_FOLDER_NAMES = {
- Environment.DIRECTORY_MUSIC,
- Environment.DIRECTORY_PODCASTS,
- Environment.DIRECTORY_RINGTONES,
- Environment.DIRECTORY_ALARMS,
- Environment.DIRECTORY_NOTIFICATIONS,
- Environment.DIRECTORY_PICTURES,
- Environment.DIRECTORY_MOVIES,
- Environment.DIRECTORY_DOWNLOADS,
- Environment.DIRECTORY_DCIM,
- Environment.DIRECTORY_DOCUMENTS,
- Environment.DIRECTORY_AUDIOBOOKS,
- };
+ public static final String[] DEFAULT_FOLDER_NAMES;
+ static {
+ if (SdkLevel.isAtLeastS()) {
+ DEFAULT_FOLDER_NAMES = new String[]{
+ Environment.DIRECTORY_MUSIC,
+ Environment.DIRECTORY_PODCASTS,
+ Environment.DIRECTORY_RINGTONES,
+ Environment.DIRECTORY_ALARMS,
+ Environment.DIRECTORY_NOTIFICATIONS,
+ Environment.DIRECTORY_PICTURES,
+ Environment.DIRECTORY_MOVIES,
+ Environment.DIRECTORY_DOWNLOADS,
+ Environment.DIRECTORY_DCIM,
+ Environment.DIRECTORY_DOCUMENTS,
+ Environment.DIRECTORY_AUDIOBOOKS,
+ Environment.DIRECTORY_RECORDINGS,
+ };
+ } else {
+ DEFAULT_FOLDER_NAMES = new String[]{
+ Environment.DIRECTORY_MUSIC,
+ Environment.DIRECTORY_PODCASTS,
+ Environment.DIRECTORY_RINGTONES,
+ Environment.DIRECTORY_ALARMS,
+ Environment.DIRECTORY_NOTIFICATIONS,
+ Environment.DIRECTORY_PICTURES,
+ Environment.DIRECTORY_MOVIES,
+ Environment.DIRECTORY_DOWNLOADS,
+ Environment.DIRECTORY_DCIM,
+ Environment.DIRECTORY_DOCUMENTS,
+ Environment.DIRECTORY_AUDIOBOOKS,
+ DIRECTORY_RECORDINGS,
+ };
+ }
+ }
/**
- * Regex that matches paths for {@link MediaColumns#RELATIVE_PATH}; it
- * captures both top-level paths and sandboxed paths.
+ * Regex that matches paths for {@link MediaColumns#RELATIVE_PATH}
*/
private static final Pattern PATTERN_RELATIVE_PATH = Pattern.compile(
- "(?i)^/storage/(?:emulated/[0-9]+/|[^/]+/)(Android/sandbox/([^/]+)/)?");
+ "(?i)^/storage/(?:emulated/[0-9]+/|[^/]+/)");
/**
* Regex that matches paths under well-known storage paths.
@@ -965,6 +1018,12 @@
private static final Pattern PATTERN_VOLUME_NAME = Pattern.compile(
"(?i)^/storage/([^/]+)");
+ /**
+ * Regex that matches user-ids under well-known storage paths.
+ */
+ private static final Pattern PATTERN_USER_ID = Pattern.compile(
+ "(?i)^/storage/emulated/([0-9]+)");
+
private static final String CAMERA_RELATIVE_PATH =
String.format("%s/%s/", Environment.DIRECTORY_DCIM, "Camera");
@@ -972,6 +1031,16 @@
return fsUuid != null ? fsUuid.toLowerCase(Locale.ROOT) : null;
}
+ public static int extractUserId(@Nullable String data) {
+ if (data == null) return -1;
+ final Matcher matcher = PATTERN_USER_ID.matcher(data);
+ if (matcher.find()) {
+ return Integer.parseInt(matcher.group(1));
+ }
+
+ return -1;
+ }
+
public static @Nullable String extractVolumePath(@Nullable String data) {
if (data == null) return null;
final Matcher matcher = PATTERN_RELATIVE_PATH.matcher(data);
@@ -1326,12 +1395,42 @@
return false;
}
+ if (isScreenshotsDirNonHidden(relativePath, name)) {
+ nomedia.delete();
+ return false;
+ }
+
// .nomedia is present which makes this directory as hidden directory
Logging.logPersistent("Observed non-standard " + nomedia);
return true;
}
/**
+ * Consider Screenshots directory in root directory or inside well-known directory as always
+ * non-hidden. Nomedia file in these directories will not be able to hide these directories.
+ * i.e., some examples of directories that will be considered non-hidden are
+ * <ul>
+ * <li> /storage/emulated/0/Screenshots or
+ * <li> /storage/emulated/0/DCIM/Screenshots or
+ * <li> /storage/emulated/0/Pictures/Screenshots ...
+ * </ul>
+ * Some examples of directories that can be considered as hidden with nomedia are
+ * <ul>
+ * <li> /storage/emulated/0/foo/Screenshots or
+ * <li> /storage/emulated/0/DCIM/Foo/Screenshots or
+ * <li> /storage/emulated/0/Pictures/foo/bar/Screenshots ...
+ * </ul>
+ */
+ private static boolean isScreenshotsDirNonHidden(@NonNull String[] relativePath,
+ @NonNull String name) {
+ if (name.equalsIgnoreCase(Environment.DIRECTORY_SCREENSHOTS)) {
+ return (relativePath.length == 1 &&
+ (TextUtils.isEmpty(relativePath[0]) || isDefaultDirectoryName(relativePath[0])));
+ }
+ return false;
+ }
+
+ /**
* Test if this given file should be considered hidden.
*/
@VisibleForTesting
diff --git a/src/com/android/providers/media/util/PermissionUtils.java b/src/com/android/providers/media/util/PermissionUtils.java
index d1dd4b2..5b3639c 100644
--- a/src/com/android/providers/media/util/PermissionUtils.java
+++ b/src/com/android/providers/media/util/PermissionUtils.java
@@ -16,16 +16,19 @@
package com.android.providers.media.util;
+import static android.Manifest.permission.ACCESS_MEDIA_LOCATION;
import static android.Manifest.permission.ACCESS_MTP;
import static android.Manifest.permission.BACKUP;
import static android.Manifest.permission.INSTALL_PACKAGES;
import static android.Manifest.permission.MANAGE_EXTERNAL_STORAGE;
+import static android.Manifest.permission.MANAGE_MEDIA;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.UPDATE_DEVICE_STATS;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.OPSTR_REQUEST_INSTALL_PACKAGES;
import static android.app.AppOpsManager.OPSTR_LEGACY_STORAGE;
+import static android.app.AppOpsManager.OPSTR_NO_ISOLATED_STORAGE;
import static android.app.AppOpsManager.OPSTR_READ_MEDIA_AUDIO;
import static android.app.AppOpsManager.OPSTR_READ_MEDIA_IMAGES;
import static android.app.AppOpsManager.OPSTR_READ_MEDIA_VIDEO;
@@ -45,8 +48,6 @@
public class PermissionUtils {
- public static final String OPSTR_NO_ISOLATED_STORAGE = "android:no_isolated_storage";
-
// Callers must hold both the old and new permissions, so that we can
// handle obscure cases like when an app targets Q but was installed on
// a device that was originally running on P before being upgraded to Q.
@@ -79,13 +80,9 @@
*/
public static boolean checkPermissionManager(@NonNull Context context, int pid,
int uid, @NonNull String packageName, @Nullable String attributionTag) {
- if (checkPermissionForDataDelivery(context, MANAGE_EXTERNAL_STORAGE, pid, uid,
+ return checkPermissionForDataDelivery(context, MANAGE_EXTERNAL_STORAGE, pid, uid,
packageName, attributionTag,
- generateAppOpMessage(packageName,sOpDescription.get()))) {
- return true;
- }
- // Fallback to OPSTR_NO_ISOLATED_STORAGE app op.
- return checkNoIsolatedStorageGranted(context, uid, packageName, attributionTag);
+ generateAppOpMessage(packageName,sOpDescription.get()));
}
/**
@@ -119,10 +116,34 @@
generateAppOpMessage(packageName,sOpDescription.get()));
}
- public static boolean checkIsLegacyStorageGranted(
- @NonNull Context context, int uid, String packageName) {
- return context.getSystemService(AppOpsManager.class)
- .unsafeCheckOp(OPSTR_LEGACY_STORAGE, uid, packageName) == MODE_ALLOWED;
+ /**
+ * Check if the given package has been granted the
+ * android.Manifest.permission#ACCESS_MEDIA_LOCATION permission.
+ */
+ public static boolean checkPermissionAccessMediaLocation(@NonNull Context context, int pid,
+ int uid, @NonNull String packageName, @Nullable String attributionTag) {
+ return checkPermissionForDataDelivery(context, ACCESS_MEDIA_LOCATION, pid, uid, packageName,
+ attributionTag, generateAppOpMessage(packageName, sOpDescription.get()));
+ }
+
+ /**
+ * Check if the given package has been granted the
+ * android.Manifest.permission#MANAGE_MEDIA permission.
+ */
+ public static boolean checkPermissionManageMedia(@NonNull Context context, int pid, int uid,
+ @NonNull String packageName, @Nullable String attributionTag) {
+ return checkPermissionForDataDelivery(context, MANAGE_MEDIA, pid, uid, packageName,
+ attributionTag, generateAppOpMessage(packageName, sOpDescription.get()));
+ }
+
+ public static boolean checkIsLegacyStorageGranted(@NonNull Context context, int uid,
+ String packageName, @Nullable String attributionTag) {
+ if (context.getSystemService(AppOpsManager.class)
+ .unsafeCheckOp(OPSTR_LEGACY_STORAGE, uid, packageName) == MODE_ALLOWED) {
+ return true;
+ }
+ // Check OPSTR_NO_ISOLATED_STORAGE app op.
+ return checkNoIsolatedStorageGranted(context, uid, packageName, attributionTag);
}
public static boolean checkPermissionReadAudio(@NonNull Context context, int pid, int uid,
@@ -408,6 +429,7 @@
private static boolean isAppOpPermission(String permission) {
switch (permission) {
case MANAGE_EXTERNAL_STORAGE:
+ case MANAGE_MEDIA:
return true;
}
return false;
@@ -415,6 +437,7 @@
private static boolean isRuntimePermission(String permission) {
switch (permission) {
+ case ACCESS_MEDIA_LOCATION:
case READ_EXTERNAL_STORAGE:
case WRITE_EXTERNAL_STORAGE:
return true;
diff --git a/src/com/android/providers/media/util/UserCache.java b/src/com/android/providers/media/util/UserCache.java
new file mode 100644
index 0000000..38d5326
--- /dev/null
+++ b/src/com/android/providers/media/util/UserCache.java
@@ -0,0 +1,152 @@
+/*
+ * 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.util;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.LongSparseArray;
+
+import androidx.annotation.GuardedBy;
+import androidx.annotation.NonNull;
+
+import com.android.modules.utils.build.SdkLevel;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * UserCache is a class that keeps track of all users that the current MediaProvider
+ * instance is responsible for. By default, it handles storage for the user it is running as,
+ * but as of Android API 31, it will also handle storage for profiles that share media
+ * with their parent - profiles for which @link{UserManager#isMediaSharedWithParent} is set.
+ *
+ * It also keeps a cache of user contexts, for improving these lookups.
+ *
+ * Note that we don't use the USER_ broadcasts for keeping this state up to date, because they
+ * aren't guaranteed to be received before the volume events for a user.
+ */
+public class UserCache {
+ final Object mLock = new Object();
+ final Context mContext;
+ final UserManager mUserManager;
+
+ @GuardedBy("mLock")
+ final LongSparseArray<Context> mUserContexts = new LongSparseArray<>();
+
+ @GuardedBy("mLock")
+ final ArrayList<UserHandle> mUsers = new ArrayList<>();
+
+ public UserCache(Context context) {
+ mContext = context;
+ mUserManager = context.getSystemService(UserManager.class);
+
+ update();
+ }
+
+ private void update() {
+ List<UserHandle> profiles = mUserManager.getEnabledProfiles();
+ synchronized (mLock) {
+ mUsers.clear();
+ // Add the user we're running as by default
+ mUsers.add(Process.myUserHandle());
+ if (!SdkLevel.isAtLeastS()) {
+ // Before S, we only handle the owner user
+ return;
+ }
+ // And find all profiles that share media with us
+ for (UserHandle profile : profiles) {
+ if (!profile.equals(mContext.getUser())) {
+ // Check if it's a profile that shares media with us
+ Context userContext = getContextForUser(profile);
+ if (userContext.getSystemService(UserManager.class).isMediaSharedWithParent()) {
+ mUsers.add(profile);
+ }
+ }
+ }
+ }
+ }
+
+ public @NonNull List<UserHandle> updateAndGetUsers() {
+ update();
+ synchronized (mLock) {
+ return (List<UserHandle>) mUsers.clone();
+ }
+ }
+
+ public @NonNull List<UserHandle> getUsersCached() {
+ synchronized (mLock) {
+ return (List<UserHandle>) mUsers.clone();
+ }
+ }
+
+ public @NonNull Context getContextForUser(@NonNull UserHandle user) {
+ Context userContext;
+ synchronized (mLock) {
+ userContext = mUserContexts.get(user.getIdentifier());
+ if (userContext != null) {
+ return userContext;
+ }
+ }
+ try {
+ userContext = mContext.createPackageContextAsUser("system", 0, user);
+ synchronized (mLock) {
+ mUserContexts.put(user.getIdentifier(), userContext);
+ }
+ return userContext;
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new RuntimeException("Failed to create context for user " + user, e);
+ }
+ }
+
+ /**
+ * Returns whether the passed in user shares media with its parent (or peer).
+ *
+ * @param user user to check
+ * @return whether the user shares media with its parent
+ */
+ public boolean userSharesMediaWithParent(@NonNull UserHandle user) {
+ if (Process.myUserHandle().equals(user)) {
+ // Early return path - the owner user doesn't have a parent
+ return false;
+ }
+ boolean found = userSharesMediaWithParentCached(user);
+ if (!found) {
+ // Update the cache and try again
+ update();
+ found = userSharesMediaWithParentCached(user);
+ }
+ return found;
+ }
+
+ /**
+ * Returns whether the passed in user shares media with its parent (or peer).
+ * Note that the value returned here is based on cached data; it relies on
+ * other callers to keep the user cache up-to-date.
+ *
+ * @param user user to check
+ * @return whether the user shares media with its parent
+ */
+ public boolean userSharesMediaWithParentCached(@NonNull UserHandle user) {
+ synchronized (mLock) {
+ // It must be a user that we manage, and not equal to the main user that we run as
+ return !Process.myUserHandle().equals(user) && mUsers.contains(user);
+ }
+ }
+}
diff --git a/tests/Android.bp b/tests/Android.bp
index 25dd84a..8a0503d 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -1,8 +1,93 @@
+android_test_helper_app {
+ name: "MediaProviderTestAppForPermissionActivity",
+ manifest: "test_app/TestAppForPermissionActivity.xml",
+ srcs: [
+ "test_app/src/**/*.java",
+ "src/com/android/providers/media/util/TestUtils.java",
+ ],
+ static_libs: [
+ "cts-install-lib",
+ ],
+ sdk_version: "test_current",
+ target_sdk_version: "30",
+ min_sdk_version: "30",
+ test_suites: [
+ "device-tests",
+ "mts-mediaprovider",
+ ],
+}
+
+android_test_helper_app {
+ name: "MediaProviderTestAppWithStoragePerms",
+ manifest: "test_app/TestAppWithStoragePerms.xml",
+ srcs: [
+ "test_app/src/**/*.java",
+ "src/com/android/providers/media/util/TestUtils.java",
+ ],
+ static_libs: [
+ "cts-install-lib",
+ ],
+ sdk_version: "test_current",
+ target_sdk_version: "30",
+ min_sdk_version: "30",
+ test_suites: [
+ "device-tests",
+ "mts-mediaprovider",
+ ],
+}
+
+android_test_helper_app {
+ name: "MediaProviderTestAppWithoutPerms",
+ manifest: "test_app/TestAppWithoutPerms.xml",
+ srcs: [
+ "test_app/src/**/*.java",
+ "src/com/android/providers/media/util/TestUtils.java",
+ ],
+ static_libs: [
+ "cts-install-lib",
+ ],
+ sdk_version: "test_current",
+ target_sdk_version: "30",
+ min_sdk_version: "30",
+ test_suites: [
+ "device-tests",
+ "mts-mediaprovider",
+ ],
+}
+
+android_test_helper_app {
+ name: "LegacyMediaProviderTestApp",
+ manifest: "test_app/LegacyTestApp.xml",
+ srcs: [
+ "test_app/src/**/*.java",
+ "src/com/android/providers/media/util/TestUtils.java",
+ ],
+ static_libs: [
+ "cts-install-lib",
+ ],
+ sdk_version: "test_current",
+ target_sdk_version: "28",
+ min_sdk_version: "30",
+ test_suites: [
+ "device-tests",
+ "mts-mediaprovider",
+ ],
+}
+
// This looks a bit awkward, but we need our tests to run against either
// MediaProvider or MediaProviderGoogle, and we don't know which one is
// on the device being tested, so we can't sign our tests with a key that
// will allow instrumentation. Thus we pull all the sources we need to
// run tests against into the test itself.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "packages_providers_MediaProvider_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["packages_providers_MediaProvider_license"],
+}
+
android_test {
name: "MediaProviderTests",
test_suites: [
@@ -38,7 +123,9 @@
"androidx.test.rules",
"guava",
"mockito-target",
+ "modules-utils-build",
"truth-prebuilt",
+ "cts-install-lib",
],
certificate: "media",
@@ -51,6 +138,15 @@
"-Xep:MissingFail:ERROR",
],
},
+
+ java_resources: [
+ ":MediaProviderTestAppWithStoragePerms",
+ ":MediaProviderTestAppWithoutPerms",
+ ":MediaProviderTestAppForPermissionActivity",
+ ":LegacyMediaProviderTestApp",
+ ],
+
+ min_sdk_version: "30",
}
filegroup {
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index b5c556a..199f617 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -2,9 +2,11 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.providers.media.tests">
+ <uses-sdk android:minSdkVersion="30" android:targetSdkVersion="30" />
+
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-
+ <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
<application android:label="MediaProvider Tests">
<uses-library android:name="android.test.runner" />
diff --git a/tests/AndroidTest.xml b/tests/AndroidTest.xml
index fe7de6a..1cae732 100644
--- a/tests/AndroidTest.xml
+++ b/tests/AndroidTest.xml
@@ -16,6 +16,10 @@
<configuration description="Runs Tests for MediaProvder.">
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
<option name="test-file-name" value="MediaProviderTests.apk" />
+ <option name="test-file-name" value="MediaProviderTestAppForPermissionActivity.apk" />
+ <option name="test-file-name" value="MediaProviderTestAppWithStoragePerms.apk" />
+ <option name="test-file-name" value="MediaProviderTestAppWithoutPerms.apk" />
+ <option name="test-file-name" value="LegacyMediaProviderTestApp.apk" />
<option name="install-arg" value="-g" />
</target_preparer>
diff --git a/tests/client/Android.bp b/tests/client/Android.bp
index a5b5beb..1541da6 100644
--- a/tests/client/Android.bp
+++ b/tests/client/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "packages_providers_MediaProvider_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["packages_providers_MediaProvider_license"],
+}
+
android_test {
name: "MediaProviderClientTests",
test_suites: [
diff --git a/tests/client/AndroidManifest.xml b/tests/client/AndroidManifest.xml
index 42175b6..f770559 100644
--- a/tests/client/AndroidManifest.xml
+++ b/tests/client/AndroidManifest.xml
@@ -6,7 +6,7 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <application android:label="MediaProvider Tests">
+ <application android:label="MediaProvider Tests" android:requestRawExternalStorageAccess="true">
<uses-library android:name="android.test.runner" />
</application>
diff --git a/tests/client/AndroidTest.xml b/tests/client/AndroidTest.xml
index 22ca7d3..8ebd0a5 100644
--- a/tests/client/AndroidTest.xml
+++ b/tests/client/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="test-file-name" value="MediaProviderClientTests.apk" />
<option name="install-arg" value="-g" />
</target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
<option name="test-suite-tag" value="apct" />
<option name="test-suite-tag" value="framework-base-presubmit" />
diff --git a/tests/client/res/raw/orientation_90.jpg b/tests/client/res/raw/orientation_90.jpg
new file mode 100644
index 0000000..aefca34
--- /dev/null
+++ b/tests/client/res/raw/orientation_90.jpg
Binary files differ
diff --git a/tests/client/src/com/android/providers/media/client/DownloadProviderTest.java b/tests/client/src/com/android/providers/media/client/DownloadProviderTest.java
index e1af6f6..b25e8df 100644
--- a/tests/client/src/com/android/providers/media/client/DownloadProviderTest.java
+++ b/tests/client/src/com/android/providers/media/client/DownloadProviderTest.java
@@ -127,9 +127,6 @@
private void deleteOtherPackageExternalFiles(List<File> otherPackageDirs) throws Exception {
for (File dir: otherPackageDirs) {
executeShellCommand("rm -r " + dir.getAbsolutePath());
- // Need to wait for the directory to be deleted, as it is flaky sometimes due to the
- // race condition in rm and the next mkdir for the next test.
- pollForDirectoryToBeDeleted(dir);
}
}
@@ -157,13 +154,4 @@
() -> dir.exists(),
"Timed out while waiting for dir " + dir + " to be created");
}
-
- /**
- * Polls for directory to be deleted
- */
- private static void pollForDirectoryToBeDeleted(File dir) throws Exception {
- pollForCondition(
- () -> !dir.exists(),
- "Timed out while waiting for dir " + dir + " to be deleted");
- }
}
diff --git a/tests/client/src/com/android/providers/media/client/LegacyProviderMigrationTest.java b/tests/client/src/com/android/providers/media/client/LegacyProviderMigrationTest.java
index 831aa9b..dde3911 100644
--- a/tests/client/src/com/android/providers/media/client/LegacyProviderMigrationTest.java
+++ b/tests/client/src/com/android/providers/media/client/LegacyProviderMigrationTest.java
@@ -18,6 +18,8 @@
import static android.provider.MediaStore.rewriteToLegacy;
+import static com.google.common.truth.Truth.assertWithMessage;
+
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -36,6 +38,7 @@
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
+import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
import android.os.SystemClock;
import android.os.storage.StorageManager;
@@ -67,10 +70,12 @@
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
+import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
@@ -117,15 +122,25 @@
.appendQueryParameter("silent", "true").build();
}
- private ContentValues generateValues(int mediaType, String mimeType, String dirName) {
+ private ContentValues generateValues(int mediaType, String mimeType, String dirName)
+ throws Exception {
+ return generateValues(mediaType, mimeType, dirName, 0);
+ }
+
+ private ContentValues generateValues(int mediaType, String mimeType, String dirName, int resId)
+ throws Exception {
final Context context = InstrumentationRegistry.getContext();
final File dir = context.getSystemService(StorageManager.class)
.getStorageVolume(MediaStore.Files.getContentUri(mVolumeName)).getDirectory();
final File subDir = new File(dir, dirName);
- final File file = new File(subDir, "legacy" + System.nanoTime() + "."
+ File file = new File(subDir, "legacy" + System.nanoTime() + "."
+ MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType));
+ if (resId != 0) {
+ file = stageFile(resId, file.getAbsolutePath());
+ }
+
final ContentValues values = new ContentValues();
values.put(FileColumns.MEDIA_TYPE, mediaType);
values.put(MediaColumns.DATA, file.getAbsolutePath());
@@ -138,6 +153,25 @@
return values;
}
+ private static File stageFile(int resId, String path) throws Exception {
+ final Context context = InstrumentationRegistry.getContext();
+ final File file = new File(path);
+ try (InputStream in = context.getResources().openRawResource(resId);
+ OutputStream out = new FileOutputStream(file)) {
+ FileUtils.copy(in, out);
+ }
+ return file;
+ }
+
+ @Test
+ public void testLegacy_Orientation() throws Exception {
+ // Use an image file with orientation of 90 degrees
+ final ContentValues values = generateValues(FileColumns.MEDIA_TYPE_IMAGE,
+ "image/jpeg", Environment.DIRECTORY_PICTURES, R.raw.orientation_90);
+ values.put(MediaColumns.ORIENTATION, String.valueOf(90));
+ doLegacy(mExternalImages, values);
+ }
+
@Test
public void testLegacy_Pending() throws Exception {
final ContentValues values = generateValues(FileColumns.MEDIA_TYPE_IMAGE,
@@ -455,12 +489,31 @@
values.remove(FileColumns.DATA);
}
+ // This will delete MediaProvider data and restarts MediaProvider, and mounts storage.
clearProviders(context, ui);
+ // Make sure we do not lose the ORIENTATION column after database migration
+ // We check this column again after the scan
+ if (values.getAsString(MediaColumns.ORIENTATION) != null) {
+ assertOrientationColumn(collectionUri, values, context, legacyFile);
+ }
+
// And force a scan to confirm upgraded data survives
MediaStore.scanVolume(context.getContentResolver(),
MediaStore.getVolumeName(collectionUri));
+ assertColumnsHaveExpectedValues(collectionUri, values, context, legacyFile);
+ }
+
+ private void assertOrientationColumn(Uri collectionUri, ContentValues originalValues,
+ Context context, File legacyFile) throws Exception {
+ final ContentValues values = new ContentValues();
+ values.put(MediaColumns.ORIENTATION, (String) originalValues.get(MediaColumns.ORIENTATION));
+ assertColumnsHaveExpectedValues(collectionUri, values, context, legacyFile);
+ }
+
+ private void assertColumnsHaveExpectedValues(Uri collectionUri, ContentValues values,
+ Context context, File legacyFile) throws Exception {
// Confirm that details from legacy provider have migrated
try (ContentProviderClient modern = context.getContentResolver()
.acquireContentProviderClient(MediaStore.AUTHORITY)) {
@@ -473,13 +526,14 @@
extras.putInt(MediaStore.QUERY_ARG_MATCH_TRASHED, MediaStore.MATCH_INCLUDE);
extras.putInt(MediaStore.QUERY_ARG_MATCH_FAVORITE, MediaStore.MATCH_INCLUDE);
- try (Cursor cursor = modern.query(collectionUri, null, extras, null)) {
+ try (Cursor cursor = pollForCursor(modern, collectionUri, extras)) {
+ assertNotNull(cursor);
assertTrue(cursor.moveToFirst());
- final ContentValues actualValues = new ContentValues();
for (String key : values.keySet()) {
- actualValues.put(key, cursor.getString(cursor.getColumnIndexOrThrow(key)));
+ assertWithMessage("Checking key %s", key)
+ .that(cursor.getString(cursor.getColumnIndexOrThrow(key)))
+ .isEqualTo(values.get(key));
}
- assertEquals(values, actualValues);
}
}
}
@@ -495,6 +549,23 @@
MediaStore.waitForIdle(resolver);
}
+ private static Cursor pollForCursor(ContentProviderClient modern, Uri collectionUri,
+ Bundle extras) throws Exception {
+ Cursor cursor = null;
+ for (int i = 0; i < POLLING_TIMEOUT_MILLIS / POLLING_SLEEP_MILLIS; i++) {
+ try {
+ cursor = modern.query(collectionUri, null, extras, null);
+ return cursor;
+ } catch (IllegalArgumentException e) {
+ // try again
+ }
+ Log.v(TAG, "Waiting for..." + collectionUri);
+ SystemClock.sleep(POLLING_SLEEP_MILLIS);
+ }
+ fail("Timed out while waiting for uri " + collectionUri);
+ return cursor;
+ }
+
private static void pollForFile(File file) {
for (int i = 0; i < POLLING_TIMEOUT_MILLIS / POLLING_SLEEP_MILLIS; i++) {
if (file.exists()) return;
diff --git a/tests/client/src/com/android/providers/media/client/PerformanceTest.java b/tests/client/src/com/android/providers/media/client/PerformanceTest.java
index 72b4234..0088514 100644
--- a/tests/client/src/com/android/providers/media/client/PerformanceTest.java
+++ b/tests/client/src/com/android/providers/media/client/PerformanceTest.java
@@ -37,13 +37,16 @@
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.UiDevice;
import com.android.providers.media.tests.utils.Timer;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.BufferedWriter;
import java.io.File;
+import java.io.FileWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -56,8 +59,12 @@
/**
* Since we're right in the critical path between camera and gallery apps, we
* need to meet some pretty strict performance deadlines.
+ *
+ * This test is marked as {@code LargeTest} for it to not run in presubmit as it does not make any
+ * assertions, and any performance regressions are caught separately by Crystallball.
*/
@RunWith(AndroidJUnit4.class)
+@LargeTest
public class PerformanceTest {
private static final String TAG = "PerformanceTest";
@@ -81,19 +88,9 @@
doSingle(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, timers);
}
+ // The numbers dumped by the timers are monitored using crystalball and regressions are
+ // reported from there.
timers.dumpResults();
-
- // Verify that core actions finished within 30ms deadline
- final long actionDeadline = 30;
- assertThat(timers.actionInsert.getAverageDurationMillis()).isLessThan(actionDeadline);
- assertThat(timers.actionUpdate.getAverageDurationMillis()).isLessThan(actionDeadline);
- assertThat(timers.actionDelete.getAverageDurationMillis()).isLessThan(actionDeadline);
-
- // Verify that external notifications finished within 30ms deadline
- final long notifyDeadline = 30;
- assertThat(timers.notifyInsert.getAverageDurationMillis()).isLessThan(notifyDeadline);
- assertThat(timers.notifyUpdate.getAverageDurationMillis()).isLessThan(notifyDeadline);
- assertThat(timers.notifyDelete.getAverageDurationMillis()).isLessThan(notifyDeadline);
}
private void doSingle(Uri collection, Timers timers) throws Exception {
@@ -160,19 +157,9 @@
doBulk(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, timers);
}
+ // The numbers dumped by the timers are monitored using crystalball and regressions are
+ // reported from there.
timers.dumpResults();
-
- // Verify that core actions finished within 30ms deadline
- final long actionDeadline = 30 * COUNT_BULK;
- assertThat(timers.actionInsert.getAverageDurationMillis()).isLessThan(actionDeadline);
- assertThat(timers.actionUpdate.getAverageDurationMillis()).isLessThan(actionDeadline);
- assertThat(timers.actionDelete.getAverageDurationMillis()).isLessThan(actionDeadline);
-
- // Verify that external notifications finished within 100ms deadline
- final long notifyDeadline = 100;
- assertThat(timers.notifyInsert.getAverageDurationMillis()).isLessThan(notifyDeadline);
- assertThat(timers.notifyUpdate.getAverageDurationMillis()).isLessThan(notifyDeadline);
- assertThat(timers.notifyDelete.getAverageDurationMillis()).isLessThan(notifyDeadline);
}
private void doBulk(Uri collection, Timers timers) throws Exception {
@@ -257,7 +244,6 @@
testDirOperations_size(500);
}
- @LargeTest
@Test
public void testDirOperations_1000() throws Exception {
testDirOperations_size(1000);
@@ -265,7 +251,8 @@
private void testDirOperations_size(int size) throws Exception {
Timer createTimer = new Timer("mkdir");
- Timer readTimer = new Timer("readdir");
+ Timer readdirTimer = new Timer("readdir");
+ Timer isFileTimer = new Timer("isFile");
// We have different timers for rename dir only and rename files as we want to track the
// performance for both of the following:
// 1. Renaming a directory is significantly faster (for file managers) as we do not update
@@ -276,18 +263,23 @@
Timer renameFilesTimer = new Timer("renamefiles");
Timer deleteTimer = new Timer("rmdir");
for (int i = 0; i < COUNT_REPEAT; i++ ) {
- doDirOperations(size, createTimer, readTimer, renameDirTimer, renameFilesTimer,
- deleteTimer);
+ doDirOperations(size, createTimer, readdirTimer, isFileTimer,
+ renameDirTimer, renameFilesTimer, deleteTimer);
}
+
+ // The numbers dumped by the timers are monitored using crystalball and regressions are
+ // reported from there.
createTimer.dumpResults();
- readTimer.dumpResults();
+ readdirTimer.dumpResults();
+ isFileTimer.dumpResults();
renameDirTimer.dumpResults();
renameFilesTimer.dumpResults();
deleteTimer.dumpResults();
}
- private void doDirOperations(int size, Timer createTimer, Timer readTimer,
- Timer renameDirTimer, Timer renameFilesTimer, Timer deleteTimer) throws Exception {
+ private void doDirOperations(int size, Timer createTimer, Timer readdirTimer,
+ Timer isFileTimer, Timer renameDirTimer, Timer renameFilesTimer,
+ Timer deleteTimer) throws Exception {
createTimer.start();
File testDir = new File(new File(Environment.getExternalStorageDirectory(),
"Download"), "test_dir_" + System.nanoTime());
@@ -295,7 +287,7 @@
List<File> files = new ArrayList<>();
for (int i = 0; i < size; i++) {
File file = new File(testDir, "file_" + System.nanoTime());
- assertTrue(file.createNewFile());
+ assertThat(file.createNewFile()).isTrue();
files.add(file);
}
createTimer.stop();
@@ -303,13 +295,22 @@
File renamedTestDir = new File(new File(Environment.getExternalStorageDirectory(),
"Download"), "renamed_test_dir_" + System.nanoTime());
try {
- readTimer.start();
+ readdirTimer.start();
File[] result = testDir.listFiles();
- readTimer.stop();
- assertEquals(size, result.length);
+ readdirTimer.stop();
+ assertThat(result.length).isEqualTo(size);
+
+ // Drop cache as this info is cached in the initial lookup
+ executeDropCachesImpl();
+ // This calls into lookup libfuse method
+ isFileTimer.start();
+ for (File file: files) {
+ file.isFile();
+ }
+ isFileTimer.stop();
renameDirTimer.start();
- assertTrue(testDir.renameTo(renamedTestDir));
+ assertThat(testDir.renameTo(renamedTestDir)).isTrue();
renameDirTimer.stop();
testDir = renamedTestDir;
@@ -321,7 +322,7 @@
List<File> renamedFiles = new ArrayList<>();
for (File file : files) {
File newFile = new File(testDir, "file_" + System.nanoTime());
- assertTrue(file.renameTo(newFile));
+ assertThat(file.renameTo(newFile)).isTrue();
renamedFiles.add(newFile);
}
renameFilesTimer.stop();
@@ -331,9 +332,9 @@
} finally {
deleteTimer.start();
for (File file : files) {
- assertTrue(file.delete());
+ assertThat(file.delete()).isTrue();
}
- assertTrue(testDir.delete());
+ assertThat(testDir.delete()).isTrue();
deleteTimer.stop();
}
}
@@ -414,4 +415,32 @@
.unregisterContentObserver(this);
}
}
+
+ /**
+ * Drops the disk cache.
+ */
+ private void executeDropCachesImpl() throws Exception {
+ // Create a temporary file which contains the dropCaches command.
+ // Do this because we cannot write to /proc/sys/vm/drop_caches directly,
+ // as executeShellCommand parses the '>' character as a literal.
+ File outputDir = InstrumentationRegistry.getInstrumentation().
+ getContext().getCacheDir();
+ File outputFile = File.createTempFile("drop_cache_script", ".sh", outputDir);
+ outputFile.setWritable(true);
+ outputFile.setExecutable(true, /*ownersOnly*/false);
+
+ String dropCacheScriptPath = outputFile.toString();
+
+ // If this works correctly, the next log-line will print 'Success'.
+ String dropCacheCmd = "sync; echo 3 > /proc/sys/vm/drop_caches "
+ + "&& echo Success || echo Failure";
+ BufferedWriter writer = new BufferedWriter(new FileWriter(dropCacheScriptPath));
+ writer.write(dropCacheCmd);
+ writer.close();
+
+ String result = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()).
+ executeShellCommand(dropCacheScriptPath);
+ Log.v(TAG, "dropCaches output was: " + result);
+ outputFile.delete();
+ }
}
diff --git a/tests/client/src/com/android/providers/media/client/PublicVolumeTest.java b/tests/client/src/com/android/providers/media/client/PublicVolumeTest.java
new file mode 100644
index 0000000..def72f7
--- /dev/null
+++ b/tests/client/src/com/android/providers/media/client/PublicVolumeTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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.client;
+
+import static com.android.providers.media.client.PublicVolumeSetupHelper.createNewPublicVolume;
+import static com.android.providers.media.client.PublicVolumeSetupHelper.deletePublicVolumes;
+import static com.android.providers.media.client.PublicVolumeSetupHelper.mountPublicVolume;
+import static com.android.providers.media.client.PublicVolumeSetupHelper.unmountPublicVolume;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertNotNull;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.MediaStore;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.OutputStream;
+
+@RunWith(AndroidJUnit4.class)
+public class PublicVolumeTest {
+ @BeforeClass
+ public static void setUp() throws Exception {
+ createNewPublicVolume();
+ }
+
+ @AfterClass
+ public static void tearDown() throws Exception {
+ deletePublicVolumes();
+ }
+
+ /**
+ * Test that we can query database rows of recently unmounted volume
+ */
+ @Test
+ public void testIncludeRecentlyUnmountedVolumes() throws Exception {
+ Context context = InstrumentationRegistry.getTargetContext();
+ ContentResolver contentResolver = context.getContentResolver();
+ MediaStore.waitForIdle(contentResolver);
+ final String displayName = "UnmountedVolumeTest" + System.nanoTime();
+
+ // Create image files in all volumes
+ for (String volumeName : MediaStore.getExternalVolumeNames(context)) {
+ ContentValues values = new ContentValues();
+ values.clear();
+ values.put(MediaStore.MediaColumns.DISPLAY_NAME, displayName + ".jpeg");
+
+ final Uri targetUri = contentResolver.insert(
+ MediaStore.Images.Media.getContentUri(volumeName), values);
+ assertNotNull(targetUri);
+
+ try (OutputStream out = contentResolver.openOutputStream(targetUri)) {
+ }
+ }
+
+ final int volumeCount = MediaStore.getExternalVolumeNames(context).size();
+ Bundle extras = new Bundle();
+ // Filter only image files added by this test
+ extras.putString(ContentResolver.QUERY_ARG_SQL_SELECTION,
+ MediaStore.MediaColumns.DISPLAY_NAME + " LIKE ?");
+ extras.putStringArray(ContentResolver.QUERY_ARG_SQL_SELECTION_ARGS,
+ new String[] {displayName + "%"});
+ // Verify that we can see both image files.
+ try (Cursor c = contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+ new String[]{MediaStore.MediaColumns._ID}, extras, null)) {
+ assertThat(c.getCount()).isEqualTo(volumeCount);
+ }
+
+ unmountPublicVolume();
+
+ // Verify that we don't see image file of unmounted volume.
+ try (Cursor c = contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+ new String[]{MediaStore.MediaColumns._ID}, extras, null)) {
+ assertThat(c.getCount()).isEqualTo(volumeCount - 1);
+ }
+
+ // Verify that querying with QUERY_ARG_INCLUDE_RECENTLY_UNMOUNTED_VOLUMES
+ // includes database rows of unmounted volume.
+ extras.putBoolean(MediaStore.QUERY_ARG_INCLUDE_RECENTLY_UNMOUNTED_VOLUMES, true);
+ try (Cursor c = contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+ new String[]{MediaStore.MediaColumns._ID}, extras, null)) {
+ assertThat(c.getCount()).isEqualTo(volumeCount);
+ }
+
+ // Mount public volume to avoid side effects to other tests which reuse
+ // the same public volume
+ mountPublicVolume();
+ }
+}
+
diff --git a/tests/src/com/android/providers/media/DatabaseHelperTest.java b/tests/src/com/android/providers/media/DatabaseHelperTest.java
index 95a1f95..a159fd0 100644
--- a/tests/src/com/android/providers/media/DatabaseHelperTest.java
+++ b/tests/src/com/android/providers/media/DatabaseHelperTest.java
@@ -27,11 +27,13 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import android.Manifest;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
+import android.os.UserHandle;
import android.provider.Column;
import android.provider.MediaStore.Audio.AudioColumns;
import android.provider.MediaStore.Files.FileColumns;
@@ -68,6 +70,8 @@
@Before
public void setUp() {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .adoptShellPermissionIdentity(Manifest.permission.INTERACT_ACROSS_USERS);
final Context context = InstrumentationRegistry.getTargetContext();
sIsolatedContext = new IsolatedContext(context, TAG, /*asFuseThread*/ false);
sIsolatedResolver = sIsolatedContext.getContentResolver();
@@ -346,17 +350,6 @@
{
final ContentValues values = new ContentValues();
values.put(FileColumns.DATA,
- "/storage/0000-0000/Android/sandbox/com.example2/Download/dir/foo.mp4");
- values.put(FileColumns.DATE_ADDED, System.currentTimeMillis());
- values.put(FileColumns.DATE_MODIFIED, System.currentTimeMillis());
- values.put(FileColumns.DISPLAY_NAME, "foo.mp4");
- values.put(FileColumns.MEDIA_TYPE, FileColumns.MEDIA_TYPE_VIDEO);
- values.put(FileColumns.MIME_TYPE, "video/mp4");
- assertFalse(db.insert("files", FileColumns.DATA, values) == -1);
- }
- {
- final ContentValues values = new ContentValues();
- values.put(FileColumns.DATA,
"/storage/emulated/0/Download/foo");
values.put(FileColumns.DATE_ADDED, System.currentTimeMillis());
values.put(FileColumns.DATE_MODIFIED, System.currentTimeMillis());
@@ -406,18 +399,6 @@
c.getString(c.getColumnIndexOrThrow(FileColumns.OWNER_PACKAGE_NAME)));
assertEquals("1", c.getString(c.getColumnIndexOrThrow(FileColumns.IS_DOWNLOAD)));
}
- try (Cursor c = db.query("files", null, FileColumns.DISPLAY_NAME + "='foo.mp4'",
- null, null, null, null)) {
- assertEquals(1, c.getCount());
- assertTrue(c.moveToFirst());
- assertEquals("/storage/0000-0000/Android/sandbox/com.example2/Download/dir/foo.mp4",
- c.getString(c.getColumnIndexOrThrow(FileColumns.DATA)));
- assertEquals("video/mp4",
- c.getString(c.getColumnIndexOrThrow(FileColumns.MIME_TYPE)));
- assertEquals("com.example2",
- c.getString(c.getColumnIndexOrThrow(FileColumns.OWNER_PACKAGE_NAME)));
- assertEquals("1", c.getString(c.getColumnIndexOrThrow(FileColumns.IS_DOWNLOAD)));
- }
try (Cursor c = db.query("files", null,
FileColumns.DATA + "='/storage/emulated/0/Download/foo'",
null, null, null, null)) {
@@ -513,6 +494,37 @@
}
}
+ @Test
+ public void testAddUserId() throws Exception {
+ try (DatabaseHelper helper = new DatabaseHelperR(sIsolatedContext, TEST_UPGRADE_DB)) {
+ SQLiteDatabase db = helper.getWritableDatabaseForTest();
+ {
+ // Insert a row before database upgrade.
+ final ContentValues values = new ContentValues();
+ values.put(FileColumns.DATA, "/storage/emulated/0/DCIM/test.jpg");
+ assertThat(db.insert("files", FileColumns.DATA, values)).isNotEqualTo(-1);
+ }
+ }
+
+ try (DatabaseHelper helper = new DatabaseHelperS(sIsolatedContext, TEST_UPGRADE_DB)) {
+ SQLiteDatabase db = helper.getWritableDatabaseForTest();
+ // Insert a row in the new version as well
+ final ContentValues values = new ContentValues();
+ values.put(FileColumns.DATA, "/storage/emulated/0/DCIM/test2.jpg");
+ assertThat(db.insert("files", FileColumns.DATA, values)).isNotEqualTo(-1);
+
+ try (Cursor cr = db.query("files", new String[]{FileColumns._USER_ID}, null, null,
+ null, null, null)) {
+ assertEquals(2, cr.getCount());
+ while (cr.moveToNext()) {
+ // Verify that after db upgrade, for all database rows (new inserts and
+ // upgrades), we set the _user_id
+ assertThat(cr.getInt(0)).isEqualTo(UserHandle.myUserId());
+ }
+ }
+ }
+ }
+
private static String normalize(String sql) {
return sql != null ? sql.replace(", ", ",") : null;
}
diff --git a/tests/src/com/android/providers/media/IdleServiceTest.java b/tests/src/com/android/providers/media/IdleServiceTest.java
index 9b0b169..064a4f8 100644
--- a/tests/src/com/android/providers/media/IdleServiceTest.java
+++ b/tests/src/com/android/providers/media/IdleServiceTest.java
@@ -90,6 +90,11 @@
final Context context = InstrumentationRegistry.getTargetContext();
final ContentResolver resolver = context.getContentResolver();
+ // Previous tests (like DatabaseHelperTest) may have left stale
+ // .database_uuid files, do an idle run first to clean them up.
+ runIdleMaintenance(resolver);
+ MediaStore.waitForIdle(resolver);
+
final File dir = Environment.getExternalStorageDirectory();
final File mediaDir = context.getExternalMediaDirs()[0];
diff --git a/tests/src/com/android/providers/media/LocalCallingIdentityTest.java b/tests/src/com/android/providers/media/LocalCallingIdentityTest.java
index e30ed92..40e1175 100644
--- a/tests/src/com/android/providers/media/LocalCallingIdentityTest.java
+++ b/tests/src/com/android/providers/media/LocalCallingIdentityTest.java
@@ -29,6 +29,7 @@
import org.junit.AfterClass;
import org.junit.BeforeClass;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -86,6 +87,7 @@
}
@Test
+ @Ignore("b/179675679")
public void testFromExternal() throws Exception {
final Context context = InstrumentationRegistry.getContext();
final PackageManager pm = context.getPackageManager();
diff --git a/tests/src/com/android/providers/media/MediaDocumentsProviderTest.java b/tests/src/com/android/providers/media/MediaDocumentsProviderTest.java
index 2db98b9..f9754e8 100644
--- a/tests/src/com/android/providers/media/MediaDocumentsProviderTest.java
+++ b/tests/src/com/android/providers/media/MediaDocumentsProviderTest.java
@@ -63,7 +63,8 @@
public void setUp() {
InstrumentationRegistry.getInstrumentation().getUiAutomation()
.adoptShellPermissionIdentity(Manifest.permission.LOG_COMPAT_CHANGE,
- Manifest.permission.READ_COMPAT_CHANGE_CONFIG);
+ Manifest.permission.READ_COMPAT_CHANGE_CONFIG,
+ Manifest.permission.INTERACT_ACROSS_USERS);
}
@After
diff --git a/tests/src/com/android/providers/media/MediaProviderForFuseTest.java b/tests/src/com/android/providers/media/MediaProviderForFuseTest.java
index e4d2e52..7de9834 100644
--- a/tests/src/com/android/providers/media/MediaProviderForFuseTest.java
+++ b/tests/src/com/android/providers/media/MediaProviderForFuseTest.java
@@ -58,7 +58,8 @@
InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
Manifest.permission.LOG_COMPAT_CHANGE,
Manifest.permission.READ_COMPAT_CHANGE_CONFIG,
- Manifest.permission.UPDATE_APP_OPS_STATS);
+ Manifest.permission.UPDATE_APP_OPS_STATS,
+ Manifest.permission.INTERACT_ACROSS_USERS);
final Context context = InstrumentationRegistry.getTargetContext();
sIsolatedContext = new IsolatedContext(context, "modern", /*asFuseThread*/ true);
@@ -95,12 +96,11 @@
file.createNewFile();
// We can write our file
- Truth.assertThat(sMediaProvider.isOpenAllowedForFuse(
- file.getPath(), sTestUid, true)).isEqualTo(0);
-
- // We should have no redaction
- Truth.assertThat(sMediaProvider.getRedactionRangesForFuse(
- file.getPath(), sTestUid, 0)).isEqualTo(new long[0]);
+ FileOpenResult result = sMediaProvider.onFileOpenForFuse(
+ file.getPath(), file.getPath(), sTestUid, 0 /* tid */, 0 /* transforms_reason */,
+ true /* forWrite */, false /* redact */, false /* transcode_metrics */);
+ Truth.assertThat(result.status).isEqualTo(0);
+ Truth.assertThat(result.redactionRanges).isEqualTo(new long[0]);
// We can rename our file
final File renamed = new File(sTestDir, "renamed" + System.nanoTime() + ".jpg");
diff --git a/tests/src/com/android/providers/media/MediaProviderTest.java b/tests/src/com/android/providers/media/MediaProviderTest.java
index 7348462..e18fc4e 100644
--- a/tests/src/com/android/providers/media/MediaProviderTest.java
+++ b/tests/src/com/android/providers/media/MediaProviderTest.java
@@ -44,12 +44,14 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Environment;
+import android.os.UserHandle;
import android.provider.MediaStore;
import android.provider.MediaStore.Audio.AudioColumns;
import android.provider.MediaStore.Files.FileColumns;
@@ -79,10 +81,12 @@
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.PrintWriter;
+import java.sql.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.List;
import java.util.Locale;
import java.util.regex.Pattern;
@@ -103,7 +107,9 @@
public static void setUp() {
InstrumentationRegistry.getInstrumentation().getUiAutomation()
.adoptShellPermissionIdentity(Manifest.permission.LOG_COMPAT_CHANGE,
- Manifest.permission.READ_COMPAT_CHANGE_CONFIG);
+ Manifest.permission.READ_COMPAT_CHANGE_CONFIG,
+ Manifest.permission.READ_DEVICE_CONFIG,
+ Manifest.permission.INTERACT_ACROSS_USERS);
final Context context = InstrumentationRegistry.getTargetContext();
sIsolatedContext = new IsolatedContext(context, "modern", /*asFuseThread*/ false);
@@ -491,8 +497,6 @@
getPathOwnerPackageName("/storage/emulated/0/Android/obb/com.example/foo.jpg"));
assertEquals("com.example",
getPathOwnerPackageName("/storage/emulated/0/Android/media/com.example/foo.jpg"));
- assertEquals("com.example",
- getPathOwnerPackageName("/storage/emulated/0/Android/sandbox/com.example/foo.jpg"));
}
@Test
@@ -515,6 +519,24 @@
}
@Test
+ public void testBuildData_withUserId() throws Exception {
+ final Uri uri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
+ final ContentValues values = new ContentValues();
+ values.put(MediaColumns.DISPLAY_NAME, "test_userid");
+ values.put(MediaColumns.MIME_TYPE, "image/png");
+ Uri result = sIsolatedResolver.insert(uri, values);
+ try (Cursor c = sIsolatedResolver.query(result,
+ new String[]{MediaColumns.DISPLAY_NAME, FileColumns._USER_ID},
+ null, null)) {
+ assertNotNull(c);
+ assertEquals(1, c.getCount());
+ assertTrue(c.moveToFirst());
+ assertEquals("test_userid.png", c.getString(0));
+ assertEquals(UserHandle.myUserId(), c.getInt(1));
+ }
+ }
+
+ @Test
public void testBuildData_Primary() throws Exception {
final Uri uri = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
assertEndsWith("/DCIM/IMG_1024.JPG",
@@ -605,6 +627,10 @@
}
};
+ final ProviderInfo info = sIsolatedContext.getPackageManager()
+ .resolveContentProvider(MediaStore.AUTHORITY, PackageManager.GET_META_DATA);
+ // Attach providerInfo, to make sure mCallingIdentity can be populated
+ provider.attachInfo(sIsolatedContext, info);
final Uri uri = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
final ContentValues values = new ContentValues();
@@ -914,36 +940,19 @@
assertTrue(isDownload("/storage/emulated/0/Download/test.pdf"));
assertTrue(isDownload("/storage/emulated/0/Download/dir/foo.mp4"));
assertTrue(isDownload("/storage/0000-0000/Download/foo.txt"));
- assertTrue(isDownload(
- "/storage/emulated/0/Android/sandbox/com.example/Download/colors.png"));
- assertTrue(isDownload(
- "/storage/emulated/0/Android/sandbox/shared-com.uid.shared/Download/colors.png"));
- assertTrue(isDownload(
- "/storage/0000-0000/Android/sandbox/com.example/Download/colors.png"));
- assertTrue(isDownload(
- "/storage/0000-0000/Android/sandbox/shared-com.uid.shared/Download/colors.png"));
-
assertFalse(isDownload("/storage/emulated/0/Pictures/colors.png"));
assertFalse(isDownload("/storage/emulated/0/Pictures/Download/colors.png"));
assertFalse(isDownload("/storage/emulated/0/Android/data/com.example/Download/foo.txt"));
- assertFalse(isDownload(
- "/storage/emulated/0/Android/sandbox/com.example/dir/Download/foo.txt"));
assertFalse(isDownload("/storage/emulated/0/Download"));
- assertFalse(isDownload("/storage/emulated/0/Android/sandbox/com.example/Download"));
- assertFalse(isDownload(
- "/storage/0000-0000/Android/sandbox/shared-com.uid.shared/Download"));
}
@Test
public void testIsDownloadDir() throws Exception {
assertTrue(isDownloadDir("/storage/emulated/0/Download"));
- assertTrue(isDownloadDir("/storage/emulated/0/Android/sandbox/com.example/Download"));
assertFalse(isDownloadDir("/storage/emulated/0/Download/colors.png"));
assertFalse(isDownloadDir("/storage/emulated/0/Download/dir/"));
- assertFalse(isDownloadDir(
- "/storage/emulated/0/Android/sandbox/com.example/Download/dir/foo.txt"));
}
@Test
@@ -1004,7 +1013,6 @@
for (String top : new String[] {
"/storage/emulated/0",
- "/storage/emulated/0/Android/sandbox/com.example",
}) {
values = computeDataValues(top + "/IMG1024.JPG");
assertVolume(values, MediaStore.VOLUME_EXTERNAL_PRIMARY);
@@ -1045,6 +1053,10 @@
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
};
+ final ProviderInfo info = sIsolatedContext.getPackageManager()
+ .resolveContentProvider(MediaStore.AUTHORITY, PackageManager.GET_META_DATA);
+ // Attach providerInfo, to make sure mCallingIdentity can be populated
+ provider.attachInfo(sIsolatedContext, info);
provider.ensureFileColumns(uri, values);
assertMimetype(values, "image/png");
@@ -1353,7 +1365,7 @@
@Test
public void testNestedTransaction_applyBatch() throws Exception {
- final Uri[] uris = new Uri[] {
+ final Uri[] uris = new Uri[]{
MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL, 0),
MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY, 0),
};
@@ -1362,4 +1374,102 @@
ops.add(ContentProviderOperation.newDelete(uris[1]).build());
sIsolatedResolver.applyBatch(MediaStore.AUTHORITY, ops);
}
+
+ @Test
+ public void testRedactionForInvalidUris() throws Exception {
+ try (ContentProviderClient cpc = sIsolatedResolver
+ .acquireContentProviderClient(MediaStore.AUTHORITY)) {
+ MediaProvider mp = (MediaProvider) cpc.getLocalContentProvider();
+ final String volumeName = MediaStore.VOLUME_EXTERNAL;
+ assertNull(mp.getRedactedUri(MediaStore.Images.Media.getContentUri(volumeName)));
+ assertNull(mp.getRedactedUri(MediaStore.Video.Media.getContentUri(volumeName)));
+ assertNull(mp.getRedactedUri(MediaStore.Audio.Media.getContentUri(volumeName)));
+ assertNull(mp.getRedactedUri(MediaStore.Audio.Albums.getContentUri(volumeName)));
+ assertNull(mp.getRedactedUri(MediaStore.Audio.Artists.getContentUri(volumeName)));
+ assertNull(mp.getRedactedUri(MediaStore.Audio.Genres.getContentUri(volumeName)));
+ assertNull(mp.getRedactedUri(MediaStore.Audio.Playlists.getContentUri(volumeName)));
+ assertNull(mp.getRedactedUri(MediaStore.Downloads.getContentUri(volumeName)));
+ assertNull(mp.getRedactedUri(MediaStore.Files.getContentUri(volumeName)));
+
+ // Check with a very large value - which shouldn't be present normally (at least for
+ // tests).
+ assertNull(mp.getRedactedUri(
+ MediaStore.Images.Media.getContentUri(volumeName, Long.MAX_VALUE)));
+ }
+ }
+
+ @Test
+ public void testRedactionForInvalidAndValidUris() throws Exception {
+ final String volumeName = MediaStore.VOLUME_EXTERNAL;
+ final List<Uri> uris = new ArrayList<>();
+ uris.add(MediaStore.Images.Media.getContentUri(volumeName));
+ uris.add(MediaStore.Video.Media.getContentUri(volumeName));
+
+ final File dir = Environment
+ .getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
+ final File[] files = new File[]{
+ stage(R.raw.test_audio, new File(dir, "test" + System.nanoTime() + ".mp3")),
+ stage(R.raw.test_video_xmp,
+ new File(dir, "test" + System.nanoTime() + ".mp4")),
+ stage(R.raw.lg_g4_iso_800_jpg,
+ new File(dir, "test" + System.nanoTime() + ".jpg"))
+ };
+
+ try (ContentProviderClient cpc = sIsolatedResolver
+ .acquireContentProviderClient(MediaStore.AUTHORITY)) {
+ MediaProvider mp = (MediaProvider) cpc.getLocalContentProvider();
+ for (File file : files) {
+ uris.add(MediaStore.scanFile(sIsolatedResolver, file));
+ }
+
+ List<Uri> redactedUris = mp.getRedactedUri(uris);
+ assertEquals(uris.size(), redactedUris.size());
+ assertNull(redactedUris.get(0));
+ assertNull(redactedUris.get(1));
+ assertNotNull(redactedUris.get(2));
+ assertNotNull(redactedUris.get(3));
+ assertNotNull(redactedUris.get(4));
+ } finally {
+ for (File file : files) {
+ file.delete();
+ }
+ }
+ }
+
+ @Test
+ public void testRedactionForFileExtension() throws Exception {
+ testRedactionForFileExtension(R.raw.test_audio, ".mp3");
+ testRedactionForFileExtension(R.raw.test_video_xmp, ".mp4");
+ testRedactionForFileExtension(R.raw.lg_g4_iso_800_jpg, ".jpg");
+ }
+
+ private void testRedactionForFileExtension(int resId, String extension) throws Exception {
+ final File dir = Environment
+ .getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
+ final File file = new File(dir, "test" + System.nanoTime() + extension);
+
+ stage(resId, file);
+
+ final List<Uri> uris = new ArrayList<>();
+ uris.add(MediaStore.scanFile(sIsolatedResolver, file));
+
+
+ try (ContentProviderClient cpc = sIsolatedResolver
+ .acquireContentProviderClient(MediaStore.AUTHORITY)) {
+ final MediaProvider mp = (MediaProvider) cpc.getLocalContentProvider();
+
+ final String[] projection = new String[]{MediaColumns.DISPLAY_NAME, MediaColumns.DATA};
+ for (Uri uri : mp.getRedactedUri(uris)) {
+ try (Cursor c = sIsolatedResolver.query(uri, projection, null, null)) {
+ assertNotNull(c);
+ assertEquals(1, c.getCount());
+ assertTrue(c.moveToFirst());
+ assertTrue(c.getString(0).endsWith(extension));
+ assertTrue(c.getString(1).endsWith(extension));
+ }
+ }
+ } finally {
+ file.delete();
+ }
+ }
}
diff --git a/tests/src/com/android/providers/media/PermissionActivityTest.java b/tests/src/com/android/providers/media/PermissionActivityTest.java
index 7bbce62..6eb738e 100644
--- a/tests/src/com/android/providers/media/PermissionActivityTest.java
+++ b/tests/src/com/android/providers/media/PermissionActivityTest.java
@@ -16,6 +16,30 @@
package com.android.providers.media;
+import static android.Manifest.permission.ACCESS_MEDIA_LOCATION;
+import static android.Manifest.permission.MANAGE_APP_OPS_MODES;
+import static android.Manifest.permission.MANAGE_EXTERNAL_STORAGE;
+import static android.Manifest.permission.MANAGE_MEDIA;
+import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+import static android.Manifest.permission.UPDATE_APP_OPS_STATS;
+
+import static androidx.test.InstrumentationRegistry.getContext;
+
+import static com.android.providers.media.PermissionActivity.VERB_FAVORITE;
+import static com.android.providers.media.PermissionActivity.VERB_TRASH;
+import static com.android.providers.media.PermissionActivity.VERB_UNFAVORITE;
+import static com.android.providers.media.PermissionActivity.VERB_WRITE;
+import static com.android.providers.media.PermissionActivity.shouldShowActionDialog;
+import static com.android.providers.media.util.PermissionUtils.checkPermissionAccessMediaLocation;
+import static com.android.providers.media.util.PermissionUtils.checkPermissionManageMedia;
+import static com.android.providers.media.util.PermissionUtils.checkPermissionManager;
+import static com.android.providers.media.util.PermissionUtils.checkPermissionReadStorage;
+import static com.android.providers.media.util.TestUtils.adoptShellPermission;
+import static com.android.providers.media.util.TestUtils.dropShellPermission;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.AppOpsManager;
import android.app.Instrumentation;
import android.content.ClipData;
import android.content.ContentValues;
@@ -24,16 +48,22 @@
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
+import android.text.TextUtils;
+import androidx.annotation.NonNull;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
import androidx.test.runner.AndroidJUnit4;
import com.android.providers.media.scan.MediaScannerTest;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.File;
+import java.util.HashSet;
+import java.util.concurrent.TimeoutException;
/**
* We already have solid coverage of this logic in {@code CtsProviderTestCases},
@@ -42,6 +72,43 @@
*/
@RunWith(AndroidJUnit4.class)
public class PermissionActivityTest {
+ private static final String TEST_APP_PACKAGE_NAME =
+ "com.android.providers.media.testapp.permission";
+
+ private static final String OP_ACCESS_MEDIA_LOCATION =
+ AppOpsManager.permissionToOp(ACCESS_MEDIA_LOCATION);
+ private static final String OP_MANAGE_MEDIA =
+ AppOpsManager.permissionToOp(MANAGE_MEDIA);
+ private static final String OP_MANAGE_EXTERNAL_STORAGE =
+ AppOpsManager.permissionToOp(MANAGE_EXTERNAL_STORAGE);
+ private static final String OP_READ_EXTERNAL_STORAGE =
+ AppOpsManager.permissionToOp(READ_EXTERNAL_STORAGE);
+
+ // The list is used to restore the permissions after the test is finished.
+ // The default value for these app ops is {@link AppOpsManager#MODE_DEFAULT}
+ private static final String[] DEFAULT_OP_PERMISSION_LIST = new String[] {
+ OP_MANAGE_EXTERNAL_STORAGE,
+ OP_MANAGE_MEDIA
+ };
+
+ // The list is used to restore the permissions after the test is finished.
+ // The default value for these app ops is {@link AppOpsManager#MODE_ALLOWED}
+ private static final String[] ALLOWED_OP_PERMISSION_LIST = new String[] {
+ OP_ACCESS_MEDIA_LOCATION,
+ OP_READ_EXTERNAL_STORAGE
+ };
+
+ private static final long TIMEOUT_MILLIS = 3000;
+ private static final long SLEEP_MILLIS = 30;
+
+ private static final int TEST_APP_PID = -1;
+ private int mTestAppUid = -1;
+
+ @Before
+ public void setUp() throws Exception {
+ mTestAppUid = getContext().getPackageManager().getPackageUid(TEST_APP_PACKAGE_NAME, 0);
+ }
+
@Test
public void testSimple() throws Exception {
final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
@@ -52,6 +119,155 @@
activity.startActivityForResult(createIntent(), 42);
}
+ @Test
+ public void testShouldShowActionDialog_favorite_false() throws Exception {
+ assertThat(shouldShowActionDialog(getContext(), TEST_APP_PID, mTestAppUid,
+ TEST_APP_PACKAGE_NAME, null, VERB_FAVORITE)).isFalse();
+ }
+
+ @Test
+ public void testShouldShowActionDialog_unfavorite_false() throws Exception {
+ assertThat(shouldShowActionDialog(getContext(), TEST_APP_PID, mTestAppUid,
+ TEST_APP_PACKAGE_NAME, null, VERB_UNFAVORITE)).isFalse();
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 31, codeName = "S")
+ public void testShouldShowActionDialog_noRESAndMES_true() throws Exception {
+ final String[] enableAppOpsList = {OP_MANAGE_MEDIA};
+ final String[] disableAppOpsList = {OP_MANAGE_EXTERNAL_STORAGE, OP_READ_EXTERNAL_STORAGE};
+ adoptShellPermission(UPDATE_APP_OPS_STATS, MANAGE_APP_OPS_MODES);
+
+ try {
+ setupPermissions(mTestAppUid, enableAppOpsList, disableAppOpsList);
+
+ assertThat(shouldShowActionDialog(getContext(), TEST_APP_PID, mTestAppUid,
+ TEST_APP_PACKAGE_NAME, null, VERB_TRASH)).isTrue();
+ } finally {
+ restoreDefaultAppOpPermissions(mTestAppUid);
+ dropShellPermission();
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 31, codeName = "S")
+ public void testShouldShowActionDialog_noMANAGE_MEDIA_true() throws Exception {
+ final String[] enableAppOpsList = {OP_MANAGE_EXTERNAL_STORAGE, OP_READ_EXTERNAL_STORAGE};
+ final String[] disableAppOpsList = {OP_MANAGE_MEDIA};
+ adoptShellPermission(UPDATE_APP_OPS_STATS, MANAGE_APP_OPS_MODES);
+
+ try {
+ setupPermissions(mTestAppUid, enableAppOpsList, disableAppOpsList);
+
+ assertThat(shouldShowActionDialog(getContext(), TEST_APP_PID, mTestAppUid,
+ TEST_APP_PACKAGE_NAME, null, VERB_TRASH)).isTrue();
+ } finally {
+ restoreDefaultAppOpPermissions(mTestAppUid);
+ dropShellPermission();
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 31, codeName = "S")
+ public void testShouldShowActionDialog_hasPermissionWithRES_false() throws Exception {
+ final String[] enableAppOpsList = {OP_MANAGE_MEDIA, OP_READ_EXTERNAL_STORAGE};
+ final String[] disableAppOpsList = {OP_MANAGE_EXTERNAL_STORAGE};
+ adoptShellPermission(UPDATE_APP_OPS_STATS, MANAGE_APP_OPS_MODES);
+
+ try {
+ setupPermissions(mTestAppUid, enableAppOpsList, disableAppOpsList);
+
+ assertThat(shouldShowActionDialog(getContext(), TEST_APP_PID, mTestAppUid,
+ TEST_APP_PACKAGE_NAME, null, VERB_TRASH)).isFalse();
+ } finally {
+ restoreDefaultAppOpPermissions(mTestAppUid);
+ dropShellPermission();
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 31, codeName = "S")
+ public void testShouldShowActionDialog_hasPermissionWithMES_false() throws Exception {
+ final String[] enableAppOpsList = {OP_MANAGE_EXTERNAL_STORAGE, OP_MANAGE_MEDIA};
+ final String[] disableAppOpsList = {OP_READ_EXTERNAL_STORAGE};
+ adoptShellPermission(UPDATE_APP_OPS_STATS, MANAGE_APP_OPS_MODES);
+
+ try {
+ setupPermissions(mTestAppUid, enableAppOpsList, disableAppOpsList);
+
+ assertThat(shouldShowActionDialog(getContext(), TEST_APP_PID, mTestAppUid,
+ TEST_APP_PACKAGE_NAME, null, VERB_TRASH)).isFalse();
+ } finally {
+ restoreDefaultAppOpPermissions(mTestAppUid);
+ dropShellPermission();
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 31, codeName = "S")
+ public void testShouldShowActionDialog_writeNoACCESS_MEDIA_LOCATION_true() throws Exception {
+ final String[] enableAppOpsList =
+ {OP_MANAGE_EXTERNAL_STORAGE, OP_MANAGE_MEDIA, OP_READ_EXTERNAL_STORAGE};
+ final String[] disableAppOpsList = {OP_ACCESS_MEDIA_LOCATION};
+ adoptShellPermission(UPDATE_APP_OPS_STATS, MANAGE_APP_OPS_MODES);
+
+ try {
+ setupPermissions(mTestAppUid, enableAppOpsList, disableAppOpsList);
+
+ assertThat(shouldShowActionDialog(getContext(), TEST_APP_PID, mTestAppUid,
+ TEST_APP_PACKAGE_NAME, null, VERB_WRITE)).isTrue();
+ } finally {
+ restoreDefaultAppOpPermissions(mTestAppUid);
+ dropShellPermission();
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 31, codeName = "S")
+ public void testShouldShowActionDialog_writeHasACCESS_MEDIA_LOCATION_false() throws Exception {
+ final String[] enableAppOpsList = {
+ OP_ACCESS_MEDIA_LOCATION,
+ OP_MANAGE_EXTERNAL_STORAGE,
+ OP_MANAGE_MEDIA,
+ OP_READ_EXTERNAL_STORAGE};
+ final String[] disableAppOpsList = new String[]{};
+ adoptShellPermission(UPDATE_APP_OPS_STATS, MANAGE_APP_OPS_MODES);
+
+ try {
+ setupPermissions(mTestAppUid, enableAppOpsList, disableAppOpsList);
+
+ assertThat(shouldShowActionDialog(getContext(), TEST_APP_PID, mTestAppUid,
+ TEST_APP_PACKAGE_NAME, null, VERB_WRITE)).isFalse();
+ } finally {
+ restoreDefaultAppOpPermissions(mTestAppUid);
+ dropShellPermission();
+ }
+ }
+
+ private static void setupPermissions(int uid, @NonNull String[] enableAppOpsList,
+ @NonNull String[] disableAppOpsList) throws Exception {
+ for (String op : enableAppOpsList) {
+ modifyAppOp(uid, op, AppOpsManager.MODE_ALLOWED);
+ }
+
+ for (String op : disableAppOpsList) {
+ modifyAppOp(uid, op, AppOpsManager.MODE_ERRORED);
+ }
+
+ pollForAppOpPermissions(TEST_APP_PID, uid, enableAppOpsList, /* hasPermission= */ true);
+ pollForAppOpPermissions(TEST_APP_PID, uid, disableAppOpsList, /* hasPermission= */ false);
+ }
+
+ private static void restoreDefaultAppOpPermissions(int uid) {
+ for (String op : DEFAULT_OP_PERMISSION_LIST) {
+ modifyAppOp(uid, op, AppOpsManager.MODE_DEFAULT);
+ }
+
+ for (String op : ALLOWED_OP_PERMISSION_LIST) {
+ modifyAppOp(uid, op, AppOpsManager.MODE_ALLOWED);
+ }
+ }
+
private static Intent createIntent() throws Exception {
final Context context = InstrumentationRegistry.getContext();
@@ -67,4 +283,52 @@
intent.putExtra(MediaStore.EXTRA_CONTENT_VALUES, new ContentValues());
return intent;
}
+
+ private static void modifyAppOp(int uid, @NonNull String op, int mode) {
+ getContext().getSystemService(AppOpsManager.class).setUidMode(op, uid, mode);
+ }
+
+ private static void pollForAppOpPermissions(int pid, int uid, String[] opList,
+ boolean hasPermission) throws Exception {
+ long current = System.currentTimeMillis();
+ final long timeout = current + TIMEOUT_MILLIS;
+ final HashSet<String> checkedOpSet = new HashSet<>();
+
+ while (current < timeout && checkedOpSet.size() < opList.length) {
+ for (String op : opList) {
+ if (!checkedOpSet.contains(op) && checkPermission(op, pid, uid,
+ TEST_APP_PACKAGE_NAME, hasPermission)) {
+ checkedOpSet.add(op);
+ continue;
+ }
+ }
+ Thread.sleep(SLEEP_MILLIS);
+ current = System.currentTimeMillis();
+ }
+
+ if (checkedOpSet.size() != opList.length) {
+ throw new TimeoutException("Check AppOp permissions with " + uid + " timeout");
+ }
+ }
+
+ private static boolean checkPermission(@NonNull String op, int pid, int uid,
+ @NonNull String packageName, boolean expected) {
+ final Context context = getContext();
+
+ if (TextUtils.equals(op, OP_READ_EXTERNAL_STORAGE)) {
+ return expected == checkPermissionReadStorage(context, pid, uid, packageName,
+ /* attributionTag= */ null);
+ } else if (TextUtils.equals(op, OP_MANAGE_EXTERNAL_STORAGE)) {
+ return expected == checkPermissionManager(context, pid, uid, packageName,
+ /* attributionTag= */ null);
+ } else if (TextUtils.equals(op, OP_MANAGE_MEDIA)) {
+ return expected == checkPermissionManageMedia(context, pid, uid, packageName,
+ /* attributionTag= */ null);
+ } else if (TextUtils.equals(op, OP_ACCESS_MEDIA_LOCATION)) {
+ return expected == checkPermissionAccessMediaLocation(context, pid, uid,
+ packageName, /* attributionTag= */ null);
+ } else {
+ throw new IllegalArgumentException("checkPermission is not supported for op: " + op);
+ }
+ }
}
diff --git a/tests/src/com/android/providers/media/ResolvePlaylistTest.java b/tests/src/com/android/providers/media/ResolvePlaylistTest.java
index 0bd2850..0f6c50a 100644
--- a/tests/src/com/android/providers/media/ResolvePlaylistTest.java
+++ b/tests/src/com/android/providers/media/ResolvePlaylistTest.java
@@ -58,7 +58,8 @@
final Context context = InstrumentationRegistry.getTargetContext();
InstrumentationRegistry.getInstrumentation().getUiAutomation()
.adoptShellPermissionIdentity(Manifest.permission.LOG_COMPAT_CHANGE,
- Manifest.permission.READ_COMPAT_CHANGE_CONFIG);
+ Manifest.permission.READ_COMPAT_CHANGE_CONFIG,
+ Manifest.permission.INTERACT_ACROSS_USERS);
mDir = new File(context.getExternalMediaDirs()[0], "test_" + System.nanoTime());
mDir.mkdirs();
diff --git a/tests/src/com/android/providers/media/TranscodeHelperTest.java b/tests/src/com/android/providers/media/TranscodeHelperTest.java
new file mode 100644
index 0000000..0c2dc59
--- /dev/null
+++ b/tests/src/com/android/providers/media/TranscodeHelperTest.java
@@ -0,0 +1,168 @@
+/*
+ * 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;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.media.ApplicationMediaCapabilities;
+import android.media.MediaFormat;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Process;
+import android.provider.DeviceConfig.OnPropertiesChangedListener;
+import android.provider.MediaStore;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+
+@RunWith(AndroidJUnit4.class)
+@SdkSuppress(minSdkVersion = 31, codeName = "S")
+public class TranscodeHelperTest {
+ private static final String SOME_VALID_FILE_PATH =
+ "/storage/emulated/0/" + Environment.DIRECTORY_DCIM + "/Camera/some_filename.mp4";
+
+ private final MediaProvider mDefaultMediaProvider = new MediaProvider() {
+ @Override
+ public String getStringDeviceConfig(String key, String defaultValue) {
+ return defaultValue;
+ }
+
+ @Override
+ public boolean getBooleanDeviceConfig(String key, boolean defaultValue) {
+ return defaultValue;
+ }
+
+ @Override
+ public int getIntDeviceConfig(String key, int defaultValue) {
+ return defaultValue;
+ }
+
+ @Override
+ public void addOnPropertiesChangedListener(OnPropertiesChangedListener listener) {
+ // Ignore
+ }
+ };
+
+ private final TranscodeHelper mUnderTest = new TranscodeHelper(
+ InstrumentationRegistry.getTargetContext(), mDefaultMediaProvider);
+
+ @Test
+ public void testSupportsValidTranscodePath() {
+ List<String> filePaths = Arrays.asList(
+ "/storage/emulated/0/" + Environment.DIRECTORY_DCIM + "/Camera/filename.mp4",
+ "/storage/emulated/1/" + Environment.DIRECTORY_DCIM + "/Camera/filename.mp4",
+ "/storage/emulated/0/dcim/camera/filename.mp4");
+
+ for (String path : filePaths) {
+ assertThat(mUnderTest.supportsTranscode(path)).isTrue();
+ }
+ }
+
+ @Test
+ public void testDoesNotSupportsInvalidTranscodePath() {
+ List<String> filePaths = Arrays.asList(
+ "/storage/emulated/ab/" + Environment.DIRECTORY_DCIM + "/Camera/filename.mp4",
+ "/storage/emulated/0/" + Environment.DIRECTORY_DCIM + "/Camera/dir/filename.mp4",
+ "/storage/emulate/" + Environment.DIRECTORY_DCIM + "/Camera/filename.mp4",
+ "/storage/emulated/" + Environment.DIRECTORY_DCIM + "/Camera/filename.jpeg",
+ "/storage/emulated/0/dcmi/Camera/dir/filename.mp4");
+
+ for (String path : filePaths) {
+ assertThat(mUnderTest.supportsTranscode(path)).isFalse();
+ }
+ }
+
+ @Test
+ public void testDoesNotTranscodeForMediaProvider() {
+ int transcodeReason = mUnderTest.shouldTranscode(SOME_VALID_FILE_PATH,
+ TranscodeHelper.getMyUid(),
+ null);
+ assertThat(transcodeReason).isEqualTo(0);
+
+ Random random = new Random(System.currentTimeMillis());
+ Bundle bundle = new Bundle();
+ bundle.putInt(MediaStore.EXTRA_MEDIA_CAPABILITIES_UID, TranscodeHelper.getMyUid());
+ int randomAppUid = random.nextInt(
+ Process.LAST_APPLICATION_UID - Process.FIRST_APPLICATION_UID + 1)
+ + Process.FIRST_APPLICATION_UID;
+ transcodeReason = mUnderTest.shouldTranscode(SOME_VALID_FILE_PATH, randomAppUid, bundle);
+ assertThat(transcodeReason).isEqualTo(0);
+ }
+
+ @Test
+ public void testDoesNotTranscodeForSystemProcesses() {
+ Random random = new Random(System.currentTimeMillis());
+ int randomSystemProcessUid = random.nextInt(Process.FIRST_APPLICATION_UID);
+ int transcodeReason = mUnderTest.shouldTranscode(SOME_VALID_FILE_PATH,
+ randomSystemProcessUid, null);
+ assertThat(transcodeReason).isEqualTo(0);
+ }
+
+ @Test
+ public void testDoesNotTranscodeIfAppAcceptsOriginalFormat() {
+ Random random = new Random(System.currentTimeMillis());
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(MediaStore.EXTRA_ACCEPT_ORIGINAL_MEDIA_FORMAT, true);
+ int randomAppUid = random.nextInt(
+ Process.LAST_APPLICATION_UID - Process.FIRST_APPLICATION_UID + 1)
+ + Process.FIRST_APPLICATION_UID;
+ int transcodeReason = mUnderTest.doesAppNeedTranscoding(randomAppUid, bundle,
+ TranscodeHelper.FLAG_HEVC, 0);
+ assertThat(transcodeReason).isEqualTo(0);
+ }
+
+ @Test
+ public void testDoesNotTranscodeIfAppExtraMediaCapabilitiesHevc_supported() {
+ Random random = new Random(System.currentTimeMillis());
+ ApplicationMediaCapabilities capabilities =
+ new ApplicationMediaCapabilities.Builder().addSupportedVideoMimeType(
+ MediaFormat.MIMETYPE_VIDEO_HEVC).build();
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(MediaStore.EXTRA_MEDIA_CAPABILITIES, capabilities);
+ int randomAppUid = random.nextInt(
+ Process.LAST_APPLICATION_UID - Process.FIRST_APPLICATION_UID + 1)
+ + Process.FIRST_APPLICATION_UID;
+ int transcodeReason = mUnderTest.doesAppNeedTranscoding(randomAppUid, bundle,
+ TranscodeHelper.FLAG_HEVC, 0);
+ assertThat(transcodeReason).isEqualTo(0);
+ }
+
+ @Test
+ public void testTranscodesIfAppExtraMediaCapabilitiesHevc_unsupported() {
+ Random random = new Random(System.currentTimeMillis());
+ ApplicationMediaCapabilities capabilities =
+ new ApplicationMediaCapabilities.Builder().addUnsupportedVideoMimeType(
+ MediaFormat.MIMETYPE_VIDEO_HEVC).build();
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(MediaStore.EXTRA_MEDIA_CAPABILITIES, capabilities);
+ int randomAppUid = random.nextInt(
+ Process.LAST_APPLICATION_UID - Process.FIRST_APPLICATION_UID + 1)
+ + Process.FIRST_APPLICATION_UID;
+ int transcodeReason = mUnderTest.doesAppNeedTranscoding(randomAppUid, bundle,
+ TranscodeHelper.FLAG_HEVC, 0);
+ assertThat(transcodeReason).isEqualTo(
+ MediaProviderStatsLog.TRANSCODING_DATA__ACCESS_REASON__APP_EXTRA);
+ }
+}
diff --git a/tests/src/com/android/providers/media/metrics/StorageAccessMetricsTest.java b/tests/src/com/android/providers/media/metrics/StorageAccessMetricsTest.java
new file mode 100644
index 0000000..5be69ff
--- /dev/null
+++ b/tests/src/com/android/providers/media/metrics/StorageAccessMetricsTest.java
@@ -0,0 +1,144 @@
+/*
+ * 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.metrics;
+
+import static com.android.providers.media.metrics.StorageAccessMetrics.PackageStorageAccessStats;
+import static com.android.providers.media.metrics.StorageAccessMetrics.UID_SAMPLES_COUNT_LIMIT;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.provider.MediaStore;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class StorageAccessMetricsTest {
+
+ private static StorageAccessMetrics storageAccessMetrics;
+
+ @Before
+ public void setUp() {
+ storageAccessMetrics = new StorageAccessMetrics();
+ }
+
+ @Test
+ public void testLogMimeType() {
+ storageAccessMetrics.logMimeType(3, "my-mime-type");
+ storageAccessMetrics.logMimeType(3, null);
+ storageAccessMetrics.logMimeType(3, "my-mime-type-2");
+ storageAccessMetrics.logMimeType(3, "my-mime-type-2");
+ storageAccessMetrics.logMimeType(3, "my-mime-type-3");
+ storageAccessMetrics.logMimeType(3, "my-mime-type-2");
+ List<PackageStorageAccessStats> statsList =
+ storageAccessMetrics.getSampleStats();
+
+ assertThat(statsList).hasSize(1);
+
+ PackageStorageAccessStats stats = statsList.get(0);
+ assertThat(stats.getUid()).isEqualTo(3);
+ assertThat(stats.mTotalAccesses).isEqualTo(0);
+ assertThat(stats.mFilePathAccesses).isEqualTo(0);
+ assertThat(stats.mSecondaryStorageAccesses).isEqualTo(0);
+ assertThat(stats.mMimeTypes.stream().toArray())
+ .asList()
+ .containsExactly("my-mime-type", "my-mime-type-2", "my-mime-type-3");
+ }
+
+ @Test
+ public void testIncrementAccessViaFuse() {
+ storageAccessMetrics.logAccessViaFuse(3, "filename.txt");
+ List<PackageStorageAccessStats> statsList =
+ storageAccessMetrics.getSampleStats();
+
+ assertThat(statsList).hasSize(1);
+
+ PackageStorageAccessStats stats = statsList.get(0);
+ assertThat(stats.getUid()).isEqualTo(3);
+ assertThat(stats.mTotalAccesses).isEqualTo(0);
+ assertThat(stats.mFilePathAccesses).isEqualTo(1);
+ assertThat(stats.mSecondaryStorageAccesses).isEqualTo(0);
+ assertThat(stats.mMimeTypes.stream().toArray())
+ .asList()
+ .containsExactly("text/plain");
+ }
+
+ @Test
+ public void testIncrementAccessViaMediaProvider_externalVolumes() {
+ storageAccessMetrics.logAccessViaMediaProvider(3, MediaStore.VOLUME_EXTERNAL);
+ storageAccessMetrics.logAccessViaMediaProvider(
+ 3, MediaStore.VOLUME_EXTERNAL_PRIMARY);
+ List<PackageStorageAccessStats> statsList =
+ storageAccessMetrics.getSampleStats();
+
+ assertThat(statsList).hasSize(1);
+
+ PackageStorageAccessStats stats = statsList.get(0);
+ assertThat(stats.getUid()).isEqualTo(3);
+ assertThat(stats.mTotalAccesses).isEqualTo(2);
+ assertThat(stats.mFilePathAccesses).isEqualTo(0);
+ assertThat(stats.mSecondaryStorageAccesses).isEqualTo(0);
+ assertThat(stats.mMimeTypes.size()).isEqualTo(0);
+ }
+
+ @Test
+ public void testIncrementAccessViaMediaProvider_ignoredVolumes() {
+ storageAccessMetrics.logAccessViaMediaProvider(3, MediaStore.VOLUME_INTERNAL);
+ storageAccessMetrics.logAccessViaMediaProvider(3, MediaStore.VOLUME_DEMO);
+ storageAccessMetrics.logAccessViaMediaProvider(3, MediaStore.MEDIA_SCANNER_VOLUME);
+ List<PackageStorageAccessStats> statsList =
+ storageAccessMetrics.getSampleStats();
+
+ assertThat(statsList).isEmpty();
+ }
+
+ @Test
+ public void testIncrementAccessViaMediaProvider_secondaryVolumes() {
+ storageAccessMetrics.logAccessViaMediaProvider(3, "my-volume");
+ List<PackageStorageAccessStats> statsList =
+ storageAccessMetrics.getSampleStats();
+
+ assertThat(statsList).hasSize(1);
+
+ PackageStorageAccessStats stats = statsList.get(0);
+ assertThat(stats.getUid()).isEqualTo(3);
+ assertThat(stats.mTotalAccesses).isEqualTo(1);
+ assertThat(stats.mFilePathAccesses).isEqualTo(0);
+ assertThat(stats.mSecondaryStorageAccesses).isEqualTo(1);
+ assertThat(stats.mMimeTypes.size()).isEqualTo(0);
+ }
+
+ @Test
+ public void testUidCountGreaterThanLimit() {
+ int i = 0;
+ for (; i < UID_SAMPLES_COUNT_LIMIT; i++) {
+ storageAccessMetrics.logAccessViaFuse(i, "myfile.txt");
+ }
+ // Add 1 more
+ storageAccessMetrics.logAccessViaFuse(i, "myfile.txt");
+ // Pull stats
+ List<PackageStorageAccessStats> statsList =
+ storageAccessMetrics.getSampleStats();
+
+ assertThat(statsList).hasSize(UID_SAMPLES_COUNT_LIMIT);
+ }
+}
diff --git a/tests/src/com/android/providers/media/metrics/TranscodeMetricsTest.java b/tests/src/com/android/providers/media/metrics/TranscodeMetricsTest.java
new file mode 100644
index 0000000..8b635df
--- /dev/null
+++ b/tests/src/com/android/providers/media/metrics/TranscodeMetricsTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.metrics;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.util.StatsEvent;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class TranscodeMetricsTest {
+ private static final int UNKNOWN_ATOM_TAG = -1;
+
+ private static final TranscodeMetrics.TranscodingStatsData EMPTY_STATS_DATA =
+ new TranscodeMetrics.TranscodingStatsData(
+ "something" /* mRequestorPackage */,
+ 0 /* mAccessType */,
+ 0 /* mFileSizeBytes */,
+ 0 /* mTranscodeResult */,
+ 0 /* mTranscodeDurationMillis */,
+ 0 /* mFileDurationMillis */,
+ 0 /* mFrameRate */,
+ (short) 0 /* mAccessReason */);
+
+ @After
+ public void tearDown() {
+ // this is to reset the saved data in TranscodeMetrics.
+ TranscodeMetrics.pullStatsEvents();
+ }
+
+ @Test
+ public void testSaveStatsData_doesNotGoBeyondHardLimit() {
+ for (int i = 0; i < TranscodeMetrics.getStatsDataCountHardLimit() + 5; ++i) {
+ TranscodeMetrics.saveStatsData(EMPTY_STATS_DATA);
+ }
+ assertThat(TranscodeMetrics.getSavedStatsDataCount()).isEqualTo(
+ TranscodeMetrics.getStatsDataCountHardLimit());
+ }
+
+ @Test
+ public void testSaveStatsData_totalStatsDataCountEqualsPassedData() {
+ int totalRequestsToPass = TranscodeMetrics.getStatsDataCountHardLimit() + 5;
+ for (int i = 0; i < totalRequestsToPass; ++i) {
+ TranscodeMetrics.saveStatsData(EMPTY_STATS_DATA);
+ }
+ assertThat(TranscodeMetrics.getTotalStatsDataCount()).isEqualTo(totalRequestsToPass);
+ }
+
+ @Test
+ public void testSaveStatsData_savedStatsDataCountEqualsPassedData_withinHardLimit() {
+ int totalRequestsToPass = TranscodeMetrics.getStatsDataCountHardLimit() - 5;
+ for (int i = 0; i < totalRequestsToPass; ++i) {
+ TranscodeMetrics.saveStatsData(EMPTY_STATS_DATA);
+ }
+ assertThat(TranscodeMetrics.getSavedStatsDataCount()).isEqualTo(totalRequestsToPass);
+ }
+
+ @Test
+ public void testHandleStatsEventDataRequest_resetsData() {
+ for (int i = 0; i < TranscodeMetrics.getStatsDataCountHardLimit(); ++i) {
+ TranscodeMetrics.saveStatsData(EMPTY_STATS_DATA);
+ }
+
+ List<StatsEvent> statsEvents = TranscodeMetrics.pullStatsEvents();
+
+ assertThat(TranscodeMetrics.getSavedStatsDataCount()).isEqualTo(0);
+ assertThat(TranscodeMetrics.getTotalStatsDataCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void testHandleStatsEventDataRequest_fillsExactlySampleLimit_excessData() {
+ for (int i = 0; i < TranscodeMetrics.getStatsDataCountHardLimit(); ++i) {
+ TranscodeMetrics.saveStatsData(EMPTY_STATS_DATA);
+ }
+
+ List<StatsEvent> statsEvents = TranscodeMetrics.pullStatsEvents();
+
+ assertThat(statsEvents.size()).isEqualTo(TranscodeMetrics.getStatsDataSampleLimit());
+ }
+
+ @Test
+ public void testHandleStatsEventDataRequest_fillsExactlyAsSaved_dataWithinSampleLimit() {
+ int totalRequestsToPass = TranscodeMetrics.getStatsDataSampleLimit() - 5;
+ for (int i = 0; i < totalRequestsToPass; ++i) {
+ TranscodeMetrics.saveStatsData(EMPTY_STATS_DATA);
+ }
+
+ List<StatsEvent> statsEvents = TranscodeMetrics.pullStatsEvents();
+
+ assertThat(statsEvents.size()).isEqualTo(totalRequestsToPass);
+ }
+}
diff --git a/tests/src/com/android/providers/media/scan/LegacyMediaScannerTest.java b/tests/src/com/android/providers/media/scan/LegacyMediaScannerTest.java
index af13fb8..cf9cb39 100644
--- a/tests/src/com/android/providers/media/scan/LegacyMediaScannerTest.java
+++ b/tests/src/com/android/providers/media/scan/LegacyMediaScannerTest.java
@@ -54,7 +54,7 @@
} catch (UnsupportedOperationException expected) {
}
try {
- scanner.onDetachVolume(MediaStore.VOLUME_EXTERNAL_PRIMARY);
+ scanner.onDetachVolume(null);
fail();
} catch (UnsupportedOperationException expected) {
}
diff --git a/tests/src/com/android/providers/media/scan/MediaScannerTest.java b/tests/src/com/android/providers/media/scan/MediaScannerTest.java
index 3d28820..98cbdcc 100644
--- a/tests/src/com/android/providers/media/scan/MediaScannerTest.java
+++ b/tests/src/com/android/providers/media/scan/MediaScannerTest.java
@@ -22,6 +22,7 @@
import static org.junit.Assert.assertEquals;
+import android.Manifest;
import android.content.ContentResolver;
import android.content.Context;
import android.content.ContextWrapper;
@@ -33,6 +34,7 @@
import android.os.Environment;
import android.os.SystemClock;
import android.provider.BaseColumns;
+import android.provider.DeviceConfig.OnPropertiesChangedListener;
import android.provider.MediaStore;
import android.provider.MediaStore.MediaColumns;
import android.provider.Settings;
@@ -85,6 +87,26 @@
public boolean isFuseThread() {
return asFuseThread;
}
+
+ @Override
+ public boolean getBooleanDeviceConfig(String key, boolean defaultValue) {
+ return defaultValue;
+ }
+
+ @Override
+ public String getStringDeviceConfig(String key, String defaultValue) {
+ return defaultValue;
+ }
+
+ @Override
+ public int getIntDeviceConfig(String key, int defaultValue) {
+ return defaultValue;
+ }
+
+ @Override
+ public void addOnPropertiesChangedListener(OnPropertiesChangedListener listener) {
+ // Ignore
+ }
};
mProvider.attachInfo(this, info);
mResolver.addProvider(MediaStore.AUTHORITY, mProvider);
@@ -122,6 +144,8 @@
@Before
public void setUp() {
final Context context = InstrumentationRegistry.getTargetContext();
+ InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
+ Manifest.permission.INTERACT_ACROSS_USERS);
mLegacy = new LegacyMediaScanner(
new IsolatedContext(context, "legacy", /*asFuseThread*/ false));
diff --git a/tests/src/com/android/providers/media/scan/ModernMediaScannerTest.java b/tests/src/com/android/providers/media/scan/ModernMediaScannerTest.java
index b10de97..ca53f65 100644
--- a/tests/src/com/android/providers/media/scan/ModernMediaScannerTest.java
+++ b/tests/src/com/android/providers/media/scan/ModernMediaScannerTest.java
@@ -69,6 +69,7 @@
import android.util.Pair;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
import androidx.test.runner.AndroidJUnit4;
import com.android.providers.media.R;
@@ -114,7 +115,8 @@
final Context context = InstrumentationRegistry.getTargetContext();
InstrumentationRegistry.getInstrumentation().getUiAutomation()
.adoptShellPermissionIdentity(Manifest.permission.LOG_COMPAT_CHANGE,
- Manifest.permission.READ_COMPAT_CHANGE_CONFIG);
+ Manifest.permission.READ_COMPAT_CHANGE_CONFIG,
+ Manifest.permission.INTERACT_ACROSS_USERS);
mDir = new File(context.getExternalMediaDirs()[0], "test_" + System.nanoTime());
mDir.mkdirs();
@@ -389,15 +391,11 @@
public void testShouldScanPathAndIsPathHidden() {
for (String prefix : new String[] {
"/storage/emulated/0",
- "/storage/emulated/0/Android/sandbox/com.example",
"/storage/0000-0000",
- "/storage/0000-0000/Android/sandbox/com.example",
}) {
assertShouldScanPathAndIsPathHidden(true, false, new File(prefix));
assertShouldScanPathAndIsPathHidden(true, false, new File(prefix + "/meow"));
assertShouldScanPathAndIsPathHidden(true, false, new File(prefix + "/Android/meow"));
- assertShouldScanPathAndIsPathHidden(true, false,
- new File(prefix + "/Android/sandbox/meow"));
assertShouldScanPathAndIsPathHidden(true, true, new File(prefix + "/.meow/dir"));
@@ -413,6 +411,9 @@
new File(prefix + "/Movies/.thumbnails/meow"));
assertShouldScanPathAndIsPathHidden(false, false,
new File(prefix + "/Music/.thumbnails/meow"));
+
+ assertShouldScanPathAndIsPathHidden(false, false,
+ new File(prefix + "/.transforms/transcode"));
}
}
@@ -463,26 +464,24 @@
public void testShouldScanDirectory() throws Exception {
for (String prefix : new String[] {
"/storage/emulated/0",
- "/storage/emulated/0/Android/sandbox/com.example",
"/storage/0000-0000",
- "/storage/0000-0000/Android/sandbox/com.example",
}) {
assertShouldScanDirectory(new File(prefix));
assertShouldScanDirectory(new File(prefix + "/meow"));
assertShouldScanDirectory(new File(prefix + "/Android"));
assertShouldScanDirectory(new File(prefix + "/Android/meow"));
- assertShouldScanDirectory(new File(prefix + "/Android/sandbox"));
- assertShouldScanDirectory(new File(prefix + "/Android/sandbox/meow"));
assertShouldScanDirectory(new File(prefix + "/.meow"));
assertShouldntScanDirectory(new File(prefix + "/Android/data"));
assertShouldntScanDirectory(new File(prefix + "/Android/obb"));
+ assertShouldntScanDirectory(new File(prefix + "/Android/sandbox"));
assertShouldntScanDirectory(new File(prefix + "/Pictures/.thumbnails"));
assertShouldntScanDirectory(new File(prefix + "/Movies/.thumbnails"));
assertShouldntScanDirectory(new File(prefix + "/Music/.thumbnails"));
assertShouldScanDirectory(new File(prefix + "/DCIM/.thumbnails"));
+ assertShouldntScanDirectory(new File(prefix + "/.transforms"));
}
}
@@ -498,9 +497,7 @@
public void testIsDirectoryHidden() throws Exception {
for (String prefix : new String[] {
"/storage/emulated/0",
- "/storage/emulated/0/Android/sandbox/com.example",
"/storage/0000-0000",
- "/storage/0000-0000/Android/sandbox/com.example",
}) {
assertDirectoryNotHidden(new File(prefix));
assertDirectoryNotHidden(new File(prefix + "/meow"));
@@ -804,6 +801,26 @@
}
}
+ @Test
+ @SdkSuppress(minSdkVersion = 31, codeName = "S")
+ public void testScan_audio_recording() throws Exception {
+ final File music = new File(mDir, "Recordings");
+ final File audio = new File(music, "audio.mp3");
+
+ music.mkdirs();
+ stage(R.raw.test_audio, audio);
+
+ mModern.scanFile(audio, REASON_UNKNOWN);
+
+ try (Cursor cursor = mIsolatedResolver
+ .query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, null)) {
+ assertEquals(1, cursor.getCount());
+ cursor.moveToFirst();
+ assertEquals(1, cursor.getInt(cursor.getColumnIndex(AudioColumns.IS_RECORDING)));
+ assertEquals(0, cursor.getInt(cursor.getColumnIndex(AudioColumns.IS_MUSIC)));
+ }
+ }
+
/**
* Verify a narrow exception where we allow an {@code mp4} video file on
* disk to be indexed as an {@code m4a} audio file.
@@ -1186,7 +1203,7 @@
firstDirScan.dumpResults();
// Time taken : preVisitDirectory
- Timer noOpDirScan = new Timer("noOpDirScan");
+ Timer noOpDirScan = new Timer("noOpDirScan1");
for (int i = 0; i < COUNT_REPEAT; i++) {
noOpDirScan.start();
mModern.scanDirectory(mDir, REASON_UNKNOWN);
@@ -1196,23 +1213,21 @@
assertThat(noOpDirScan.getMaxDurationMillis()).isLessThan(
firstDirScan.getMaxDurationMillis());
- // renaming directory for non-M_E_S apps does a scan of the directory as well;
- // so subsequent scans should be noOp as the directory is not dirty.
- File renamedTestDir = new File(mIsolatedContext.getExternalMediaDirs()[0],
- "renamed_test_" + System.nanoTime());
- assertThat(mDir.renameTo(renamedTestDir)).isTrue();
+ // Creating new file in the nomedia dir by a non-M_E_S app should not set nomedia dir dirty.
+ File file = new File(mDir, "file_" + System.nanoTime());
+ assertThat(file.createNewFile()).isTrue();
- Timer renamedDirScan = new Timer("renamedDirScan");
- renamedDirScan.start();
+ // The dir should not be dirty and subsequest scans should not scan the entire directory.
// Time taken : preVisitDirectory
- mModern.scanDirectory(renamedTestDir, REASON_UNKNOWN);
- renamedDirScan.stop();
- renamedDirScan.dumpResults();
- assertThat(renamedDirScan.getMaxDurationMillis()).isLessThan(
+ noOpDirScan = new Timer("noOpDirScan2");
+ for (int i = 0; i < COUNT_REPEAT; i++) {
+ noOpDirScan.start();
+ mModern.scanDirectory(mDir, REASON_UNKNOWN);
+ noOpDirScan.stop();
+ }
+ noOpDirScan.dumpResults();
+ assertThat(noOpDirScan.getMaxDurationMillis()).isLessThan(
firstDirScan.getMaxDurationMillis());
-
- // This is essential for folder cleanup in tearDown
- mDir = renamedTestDir;
}
@Test
diff --git a/tests/src/com/android/providers/media/scan/NullMediaScannerTest.java b/tests/src/com/android/providers/media/scan/NullMediaScannerTest.java
index 44528ba..063f1b7 100644
--- a/tests/src/com/android/providers/media/scan/NullMediaScannerTest.java
+++ b/tests/src/com/android/providers/media/scan/NullMediaScannerTest.java
@@ -41,6 +41,6 @@
scanner.scanFile(new File("/dev/null"), MediaScanner.REASON_UNKNOWN,
InstrumentationRegistry.getContext().getPackageName());
- scanner.onDetachVolume(MediaStore.VOLUME_EXTERNAL_PRIMARY);
+ scanner.onDetachVolume(null);
}
}
diff --git a/tests/src/com/android/providers/media/util/PermissionUtilsTest.java b/tests/src/com/android/providers/media/util/PermissionUtilsTest.java
index 1eba379..c434bd2 100644
--- a/tests/src/com/android/providers/media/util/PermissionUtilsTest.java
+++ b/tests/src/com/android/providers/media/util/PermissionUtilsTest.java
@@ -16,8 +16,29 @@
package com.android.providers.media.util;
+import static android.Manifest.permission.MANAGE_APP_OPS_MODES;
+import static android.Manifest.permission.MANAGE_EXTERNAL_STORAGE;
+import static android.Manifest.permission.MANAGE_MEDIA;
+import static android.Manifest.permission.UPDATE_APP_OPS_STATS;
+import static android.app.AppOpsManager.OPSTR_NO_ISOLATED_STORAGE;
+import static android.app.AppOpsManager.OPSTR_READ_MEDIA_AUDIO;
+import static android.app.AppOpsManager.OPSTR_READ_MEDIA_IMAGES;
+import static android.app.AppOpsManager.OPSTR_READ_MEDIA_VIDEO;
+import static android.app.AppOpsManager.OPSTR_REQUEST_INSTALL_PACKAGES;
+import static android.app.AppOpsManager.OPSTR_WRITE_MEDIA_AUDIO;
+import static android.app.AppOpsManager.OPSTR_WRITE_MEDIA_IMAGES;
+import static android.app.AppOpsManager.OPSTR_WRITE_MEDIA_VIDEO;
+
+import static androidx.test.InstrumentationRegistry.getContext;
+
+import static com.android.providers.media.util.PermissionUtils.checkAppOpRequestInstallPackagesForSharedUid;
+import static com.android.providers.media.util.PermissionUtils.checkIsLegacyStorageGranted;
import static com.android.providers.media.util.PermissionUtils.checkNoIsolatedStorageGranted;
+import static com.android.providers.media.util.PermissionUtils.checkPermissionAccessMediaLocation;
+import static com.android.providers.media.util.PermissionUtils.checkPermissionAccessMtp;
import static com.android.providers.media.util.PermissionUtils.checkPermissionDelegator;
+import static com.android.providers.media.util.PermissionUtils.checkPermissionInstallPackages;
+import static com.android.providers.media.util.PermissionUtils.checkPermissionManageMedia;
import static com.android.providers.media.util.PermissionUtils.checkPermissionManager;
import static com.android.providers.media.util.PermissionUtils.checkPermissionReadAudio;
import static com.android.providers.media.util.PermissionUtils.checkPermissionReadImages;
@@ -29,20 +50,49 @@
import static com.android.providers.media.util.PermissionUtils.checkPermissionWriteImages;
import static com.android.providers.media.util.PermissionUtils.checkPermissionWriteStorage;
import static com.android.providers.media.util.PermissionUtils.checkPermissionWriteVideo;
+import static com.android.providers.media.util.PermissionUtils.checkWriteImagesOrVideoAppOps;
+import static com.android.providers.media.util.TestUtils.QUERY_TYPE;
+import static com.android.providers.media.util.TestUtils.RUN_INFINITE_ACTIVITY;
+import static com.android.providers.media.util.TestUtils.adoptShellPermission;
+import static com.android.providers.media.util.TestUtils.dropShellPermission;
+import static com.android.providers.media.util.TestUtils.getPid;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import android.app.AppOpsManager;
import android.content.Context;
+import android.content.Intent;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
import androidx.test.runner.AndroidJUnit4;
+import com.android.cts.install.lib.TestApp;
+
+import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.HashMap;
+import java.util.Map;
+
@RunWith(AndroidJUnit4.class)
public class PermissionUtilsTest {
+ private static final TestApp TEST_APP_WITH_STORAGE_PERMS = new TestApp(
+ "TestAppWithStoragePerms",
+ "com.android.providers.media.testapp.withstorageperms", 1, false,
+ "MediaProviderTestAppWithStoragePerms.apk");
+ private static final TestApp TEST_APP_WITHOUT_PERMS = new TestApp("TestAppWithoutPerms",
+ "com.android.providers.media.testapp.withoutperms", 1, false,
+ "MediaProviderTestAppWithoutPerms.apk");
+ private static final TestApp LEGACY_TEST_APP = new TestApp("LegacyTestApp",
+ "com.android.providers.media.testapp.legacy", 1, false,
+ "LegacyMediaProviderTestApp.apk");
+
+ // Permission checks are based on uid, so we can pass -1 pid and avoid starting the test apps.
+ private static final int TEST_APP_PID = -1;
+
@Test
public void testConstructor() {
new PermissionUtils();
@@ -53,26 +103,30 @@
* we expect to be holding.
*/
@Test
- public void testSelfPermissions() throws Exception {
- final Context context = InstrumentationRegistry.getContext();
+ public void testSelfPermissions() {
+ final Context context = getContext();
final int pid = android.os.Process.myPid();
final int uid = android.os.Process.myUid();
final String packageName = context.getPackageName();
- assertTrue(checkPermissionSelf(context, pid, uid));
- assertFalse(checkPermissionShell(context, pid, uid));
- assertFalse(checkPermissionManager(context, pid, uid, packageName, null));
- assertFalse(checkPermissionDelegator(context, pid, uid));
+ assertThat(checkPermissionSelf(context, pid, uid)).isTrue();
+ assertThat(checkPermissionShell(context, pid, uid)).isFalse();
+ assertThat(checkPermissionManager(context, pid, uid, packageName, null)).isFalse();
+ assertThat(checkPermissionDelegator(context, pid, uid)).isFalse();
+ assertThat(checkPermissionManageMedia(context, pid, uid, packageName, null)).isFalse();
+ assertThat(checkPermissionAccessMediaLocation(context, pid, uid,
+ packageName, null)).isFalse();
- assertTrue(checkPermissionReadStorage(context, pid, uid, packageName, null));
- assertTrue(checkPermissionWriteStorage(context, pid, uid, packageName, null));
+ assertThat(checkPermissionReadStorage(context, pid, uid, packageName, null)).isTrue();
+ assertThat(checkPermissionWriteStorage(context, pid, uid, packageName, null)).isTrue();
- assertTrue(checkPermissionReadAudio(context, pid, uid, packageName, null));
- assertFalse(checkPermissionWriteAudio(context, pid, uid, packageName, null));
- assertTrue(checkPermissionReadVideo(context, pid, uid, packageName, null));
- assertFalse(checkPermissionWriteVideo(context, pid, uid, packageName, null));
- assertTrue(checkPermissionReadImages(context, pid, uid, packageName, null));
- assertFalse(checkPermissionWriteImages(context, pid, uid, packageName, null));
+ assertThat(checkPermissionReadAudio(context, pid, uid, packageName, null)).isTrue();
+ assertThat(checkPermissionWriteAudio(context, pid, uid, packageName, null)).isFalse();
+ assertThat(checkPermissionReadVideo(context, pid, uid, packageName, null)).isTrue();
+ assertThat(checkPermissionWriteVideo(context, pid, uid, packageName, null)).isFalse();
+ assertThat(checkPermissionReadImages(context, pid, uid, packageName, null)).isTrue();
+ assertThat(checkPermissionWriteImages(context, pid, uid, packageName, null)).isFalse();
+ assertThat(checkPermissionInstallPackages(context, pid, uid, packageName, null)).isFalse();
}
/**
@@ -80,9 +134,372 @@
*/
@Test
public void testNoIsolatedStorageIsByDefaultDenied() throws Exception {
- final Context context = InstrumentationRegistry.getContext();
+ final Context context = getContext();
final int uid = android.os.Process.myUid();
final String packageName = context.getPackageName();
- assertFalse(checkNoIsolatedStorageGranted(context, uid, packageName, null));
+ assertThat(checkNoIsolatedStorageGranted(context, uid, packageName, null)).isFalse();
+ }
+
+ @Test
+ public void testDefaultPermissionsOnTestAppWithStoragePerms() throws Exception {
+ String packageName = TEST_APP_WITH_STORAGE_PERMS.getPackageName();
+ int testAppUid = getContext().getPackageManager().getPackageUid(packageName, 0);
+ adoptShellPermission(UPDATE_APP_OPS_STATS);
+
+ try {
+ assertThat(checkPermissionSelf(getContext(), TEST_APP_PID, testAppUid)).isFalse();
+ assertThat(checkPermissionShell(getContext(), TEST_APP_PID, testAppUid)).isFalse();
+ assertThat(
+ checkIsLegacyStorageGranted(getContext(), testAppUid, packageName,
+ null)).isFalse();
+ assertThat(
+ checkPermissionInstallPackages(getContext(), TEST_APP_PID, testAppUid,
+ packageName, null)).isFalse();
+ assertThat(
+ checkPermissionAccessMtp(getContext(), TEST_APP_PID, testAppUid, packageName,
+ null)).isFalse();
+ assertThat(
+ checkPermissionWriteStorage(getContext(), TEST_APP_PID, testAppUid, packageName,
+ null)).isTrue();
+ checkReadPermissions(TEST_APP_PID, testAppUid, packageName, true);
+ } finally {
+ dropShellPermission();
+ }
+ }
+
+ @Test
+ public void testDefaultPermissionsOnTestAppWithoutPerms() throws Exception {
+ String packageName = TEST_APP_WITHOUT_PERMS.getPackageName();
+ int testAppUid = getContext().getPackageManager().getPackageUid(packageName, 0);
+ adoptShellPermission(UPDATE_APP_OPS_STATS);
+
+ try {
+ assertThat(checkPermissionSelf(getContext(), TEST_APP_PID, testAppUid)).isFalse();
+ assertThat(checkPermissionShell(getContext(), TEST_APP_PID, testAppUid)).isFalse();
+ assertThat(
+ checkPermissionManager(getContext(), TEST_APP_PID, testAppUid, packageName,
+ null)).isFalse();
+
+ assertThat(
+ checkPermissionManageMedia(
+ getContext(), TEST_APP_PID, testAppUid, packageName, null))
+ .isFalse();
+
+ assertThat(checkPermissionAccessMediaLocation(getContext(), TEST_APP_PID, testAppUid,
+ packageName, null)).isFalse();
+
+ assertThat(
+ checkIsLegacyStorageGranted(getContext(), testAppUid, packageName,
+ null)).isFalse();
+ assertThat(
+ checkPermissionInstallPackages(getContext(), TEST_APP_PID, testAppUid,
+ packageName,
+ null)).isFalse();
+ assertThat(
+ checkPermissionAccessMtp(getContext(), TEST_APP_PID, testAppUid, packageName,
+ null)).isFalse();
+ assertThat(
+ checkPermissionWriteStorage(getContext(), TEST_APP_PID, testAppUid, packageName,
+ null)).isFalse();
+ checkReadPermissions(TEST_APP_PID, testAppUid, packageName, false);
+ } finally {
+ dropShellPermission();
+ }
+ }
+
+ @Test
+ public void testDefaultPermissionsOnLegacyTestApp() throws Exception {
+ String packageName = LEGACY_TEST_APP.getPackageName();
+ int testAppUid = getContext().getPackageManager().getPackageUid(packageName, 0);
+ adoptShellPermission(UPDATE_APP_OPS_STATS);
+
+ try {
+ assertThat(checkPermissionSelf(getContext(), TEST_APP_PID, testAppUid)).isFalse();
+ assertThat(checkPermissionShell(getContext(), TEST_APP_PID, testAppUid)).isFalse();
+ assertThat(
+ checkPermissionManager(getContext(), TEST_APP_PID, testAppUid, packageName,
+ null)).isFalse();
+
+ assertThat(
+ checkPermissionManageMedia(
+ getContext(), TEST_APP_PID, testAppUid, packageName, null))
+ .isFalse();
+
+ assertThat(checkPermissionAccessMediaLocation(getContext(), TEST_APP_PID, testAppUid,
+ packageName, null)).isTrue();
+
+ assertThat(
+ checkIsLegacyStorageGranted(getContext(), testAppUid, packageName,
+ null)).isTrue();
+ assertThat(
+ checkPermissionInstallPackages(getContext(), TEST_APP_PID, testAppUid,
+ packageName, null)).isFalse();
+ assertThat(
+ checkPermissionAccessMtp(getContext(), TEST_APP_PID, testAppUid, packageName,
+ null)).isFalse();
+ assertThat(
+ checkPermissionWriteStorage(getContext(), TEST_APP_PID, testAppUid, packageName,
+ null)).isFalse();
+ checkReadPermissions(TEST_APP_PID, testAppUid, packageName, true);
+ } finally {
+ dropShellPermission();
+ }
+ }
+
+ @Test
+ public void testManageExternalStoragePermissionsOnTestApp() throws Exception {
+ final String packageName = TEST_APP_WITH_STORAGE_PERMS.getPackageName();
+ final int testAppUid = getContext().getPackageManager().getPackageUid(packageName, 0);
+ final String op = AppOpsManager.permissionToOp(MANAGE_EXTERNAL_STORAGE);
+ adoptShellPermission(UPDATE_APP_OPS_STATS, MANAGE_APP_OPS_MODES);
+
+ try {
+ modifyAppOp(testAppUid, op, AppOpsManager.MODE_ERRORED);
+
+ assertThat(checkPermissionManager(getContext(), TEST_APP_PID, testAppUid, packageName,
+ null)).isFalse();
+
+ modifyAppOp(testAppUid, op, AppOpsManager.MODE_ALLOWED);
+
+ assertThat(checkPermissionManager(getContext(), TEST_APP_PID, testAppUid, packageName,
+ null)).isTrue();
+ } finally {
+ dropShellPermission();
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 31, codeName = "S")
+ public void testManageMediaPermissionsOnTestApp() throws Exception {
+ final String packageName = TEST_APP_WITH_STORAGE_PERMS.getPackageName();
+ final int testAppUid = getContext().getPackageManager().getPackageUid(packageName, 0);
+ final String op = AppOpsManager.permissionToOp(MANAGE_MEDIA);
+ adoptShellPermission(UPDATE_APP_OPS_STATS, MANAGE_APP_OPS_MODES);
+
+ try {
+ modifyAppOp(testAppUid, op, AppOpsManager.MODE_ERRORED);
+
+ assertThat(
+ checkPermissionManageMedia(
+ getContext(), TEST_APP_PID, testAppUid, packageName, null))
+ .isFalse();
+
+ modifyAppOp(testAppUid, op, AppOpsManager.MODE_ALLOWED);
+
+ assertThat(
+ checkPermissionManageMedia(
+ getContext(), TEST_APP_PID, testAppUid, packageName, null))
+ .isTrue();
+ } finally {
+ dropShellPermission();
+ }
+ }
+
+ @Test
+ public void testSystemGalleryPermissionsOnTestApp() throws Exception {
+ String packageName = TEST_APP_WITH_STORAGE_PERMS.getPackageName();
+ int testAppUid = getContext().getPackageManager().getPackageUid(packageName, 0);
+ adoptShellPermission(UPDATE_APP_OPS_STATS, MANAGE_APP_OPS_MODES);
+
+ try {
+ checkPermissionsForGallery(testAppUid, TEST_APP_PID, packageName, false);
+
+ final String[] SYSTEM_GALERY_APPOPS =
+ {OPSTR_WRITE_MEDIA_IMAGES, OPSTR_WRITE_MEDIA_VIDEO};
+ for (String op : SYSTEM_GALERY_APPOPS) {
+ modifyAppOp(testAppUid, op, AppOpsManager.MODE_ALLOWED);
+ }
+ checkPermissionsForGallery(testAppUid, TEST_APP_PID, packageName, true);
+
+ for (String op : SYSTEM_GALERY_APPOPS) {
+ modifyAppOp(testAppUid, op, AppOpsManager.MODE_ERRORED);
+ }
+ checkPermissionsForGallery(testAppUid, TEST_APP_PID, packageName, false);
+ } finally {
+ dropShellPermission();
+ }
+ }
+
+ @Test
+ public void testIsolatedStoragePermissionsOnTestApp() throws Exception {
+ String packageName = TEST_APP_WITH_STORAGE_PERMS.getPackageName();
+ int testAppUid = getContext().getPackageManager().getPackageUid(packageName, 0);
+ adoptShellPermission(UPDATE_APP_OPS_STATS, MANAGE_APP_OPS_MODES);
+
+ try {
+ assertThat(
+ checkNoIsolatedStorageGranted(getContext(), testAppUid, packageName,
+ null)).isFalse();
+
+ modifyAppOp(testAppUid, OPSTR_NO_ISOLATED_STORAGE, AppOpsManager.MODE_ALLOWED);
+ assertThat(
+ checkNoIsolatedStorageGranted(getContext(), testAppUid, packageName,
+ null)).isTrue();
+
+ modifyAppOp(testAppUid, OPSTR_NO_ISOLATED_STORAGE, AppOpsManager.MODE_ERRORED);
+ assertThat(
+ checkNoIsolatedStorageGranted(getContext(), testAppUid, packageName,
+ null)).isFalse();
+ } finally {
+ dropShellPermission();
+ }
+ }
+
+ @Test
+ public void testReadVideoOnTestApp() throws Exception {
+ final String packageName = TEST_APP_WITH_STORAGE_PERMS.getPackageName();
+ int testAppUid = getContext().getPackageManager().getPackageUid(
+ packageName, 0);
+ adoptShellPermission(UPDATE_APP_OPS_STATS, MANAGE_APP_OPS_MODES);
+
+ try {
+ assertThat(
+ checkPermissionReadVideo(getContext(), TEST_APP_PID, testAppUid, packageName,
+ null)).isTrue();
+
+ modifyAppOp(testAppUid, OPSTR_READ_MEDIA_VIDEO, AppOpsManager.MODE_ERRORED);
+ assertThat(
+ checkPermissionReadVideo(getContext(), TEST_APP_PID, testAppUid, packageName,
+ null)).isFalse();
+
+ modifyAppOp(testAppUid, OPSTR_READ_MEDIA_VIDEO, AppOpsManager.MODE_ALLOWED);
+ assertThat(
+ checkPermissionReadVideo(getContext(), TEST_APP_PID, testAppUid, packageName,
+ null)).isTrue();
+ } finally {
+ dropShellPermission();
+ }
+ }
+
+ @Test
+ public void testWriteAudioOnTestApp() throws Exception {
+ final String packageName = TEST_APP_WITH_STORAGE_PERMS.getPackageName();
+ int testAppUid = getContext().getPackageManager().getPackageUid(
+ packageName, 0);
+ adoptShellPermission(UPDATE_APP_OPS_STATS, MANAGE_APP_OPS_MODES);
+
+ try {
+ assertThat(
+ checkPermissionWriteAudio(getContext(), TEST_APP_PID, testAppUid, packageName,
+ null)).isFalse();
+
+ modifyAppOp(testAppUid, OPSTR_WRITE_MEDIA_AUDIO, AppOpsManager.MODE_ALLOWED);
+ assertThat(
+ checkPermissionWriteAudio(getContext(), TEST_APP_PID, testAppUid, packageName,
+ null)).isTrue();
+
+ modifyAppOp(testAppUid, OPSTR_WRITE_MEDIA_AUDIO, AppOpsManager.MODE_ERRORED);
+ assertThat(
+ checkPermissionWriteAudio(getContext(), TEST_APP_PID, testAppUid, packageName,
+ null)).isFalse();
+ } finally {
+ dropShellPermission();
+ }
+ }
+
+ @Test
+ public void testReadAudioOnTestApp() throws Exception {
+ final String packageName = TEST_APP_WITH_STORAGE_PERMS.getPackageName();
+ int testAppUid = getContext().getPackageManager().getPackageUid(
+ packageName, 0);
+ adoptShellPermission(UPDATE_APP_OPS_STATS, MANAGE_APP_OPS_MODES);
+
+ try {
+ assertThat(
+ checkPermissionReadAudio(getContext(), TEST_APP_PID, testAppUid, packageName,
+ null)).isTrue();
+
+ modifyAppOp(testAppUid, OPSTR_READ_MEDIA_AUDIO, AppOpsManager.MODE_ERRORED);
+ assertThat(
+ checkPermissionReadAudio(getContext(), TEST_APP_PID, testAppUid, packageName,
+ null)).isFalse();
+
+ modifyAppOp(testAppUid, OPSTR_READ_MEDIA_AUDIO, AppOpsManager.MODE_ALLOWED);
+ assertThat(
+ checkPermissionReadAudio(getContext(), TEST_APP_PID, testAppUid, packageName,
+ null)).isTrue();
+ } finally {
+ dropShellPermission();
+ }
+ }
+
+ @Test
+ public void testReadImagesOnTestApp() throws Exception {
+ final String packageName = TEST_APP_WITH_STORAGE_PERMS.getPackageName();
+ int testAppUid = getContext().getPackageManager().getPackageUid(packageName, 0);
+ adoptShellPermission(UPDATE_APP_OPS_STATS, MANAGE_APP_OPS_MODES);
+
+ try {
+ assertThat(
+ checkPermissionReadImages(getContext(), TEST_APP_PID, testAppUid, packageName,
+ null)).isTrue();
+
+ modifyAppOp(testAppUid, OPSTR_READ_MEDIA_IMAGES, AppOpsManager.MODE_ERRORED);
+ assertThat(
+ checkPermissionReadImages(getContext(), TEST_APP_PID, testAppUid, packageName,
+ null)).isFalse();
+
+ modifyAppOp(testAppUid, OPSTR_READ_MEDIA_IMAGES, AppOpsManager.MODE_ALLOWED);
+ assertThat(
+ checkPermissionReadImages(getContext(), TEST_APP_PID, testAppUid, packageName,
+ null)).isTrue();
+ } finally {
+ dropShellPermission();
+ }
+ }
+
+ @Test
+ public void testOpstrInstallPermissionsOnTestApp() throws Exception {
+ int testAppUid = getContext().getPackageManager().getPackageUid(
+ TEST_APP_WITH_STORAGE_PERMS.getPackageName(), 0);
+ String[] packageName = {TEST_APP_WITH_STORAGE_PERMS.getPackageName()};
+ adoptShellPermission(UPDATE_APP_OPS_STATS, MANAGE_APP_OPS_MODES);
+
+ try {
+ assertThat(
+ checkAppOpRequestInstallPackagesForSharedUid(getContext(), testAppUid,
+ packageName, null)).isFalse();
+
+ modifyAppOp(testAppUid, OPSTR_REQUEST_INSTALL_PACKAGES, AppOpsManager.MODE_ALLOWED);
+ assertThat(
+ checkAppOpRequestInstallPackagesForSharedUid(getContext(), testAppUid,
+ packageName, null)).isTrue();
+
+ modifyAppOp(testAppUid, OPSTR_REQUEST_INSTALL_PACKAGES, AppOpsManager.MODE_ERRORED);
+ assertThat(
+ checkAppOpRequestInstallPackagesForSharedUid(getContext(), testAppUid,
+ packageName, null)).isFalse();
+ } finally {
+ dropShellPermission();
+ }
+ }
+
+ static private void modifyAppOp(int uid, String op, int mode) {
+ getContext().getSystemService(AppOpsManager.class).setUidMode(op, uid, mode);
+ }
+
+ static private void checkPermissionsForGallery(int uid, int pid, String packageName,
+ boolean expected) {
+ assertEquals(expected,
+ checkWriteImagesOrVideoAppOps(getContext(), uid, packageName, null));
+ assertEquals(expected,
+ checkPermissionWriteImages(getContext(), pid, uid, packageName, null));
+ assertEquals(expected,
+ checkPermissionWriteVideo(getContext(), pid, uid, packageName, null));
+ assertThat(
+ checkPermissionWriteAudio(getContext(), pid, uid, packageName, null))
+ .isFalse();
+ }
+
+ static private void checkReadPermissions(int pid, int uid, String packageName,
+ boolean expected) {
+ assertEquals(expected,
+ checkPermissionReadStorage(getContext(), pid, uid, packageName, null));
+ assertEquals(expected,
+ checkPermissionReadAudio(getContext(), pid, uid, packageName, null));
+ assertEquals(expected,
+ checkPermissionReadImages(getContext(), pid, uid, packageName, null));
+ assertEquals(expected,
+ checkPermissionReadVideo(getContext(), pid, uid, packageName, null));
}
}
diff --git a/tests/src/com/android/providers/media/util/TestUtils.java b/tests/src/com/android/providers/media/util/TestUtils.java
new file mode 100644
index 0000000..f2d3696
--- /dev/null
+++ b/tests/src/com/android/providers/media/util/TestUtils.java
@@ -0,0 +1,58 @@
+/*
+ * 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.util;
+
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
+import android.support.test.uiautomator.UiDevice;
+
+import androidx.annotation.NonNull;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+public class TestUtils {
+ public static final String QUERY_TYPE = "com.android.providers.media.util.QUERY_TYPE";
+ public static final String RUN_INFINITE_ACTIVITY =
+ "com.android.providers.media.util.RUN_INFINITE_ACTIVITY";
+
+ private static final long POLLING_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(20);
+ private static final long POLLING_SLEEP_MILLIS = 100;
+
+ public static void adoptShellPermission(@NonNull String... perms) {
+ getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(perms);
+ }
+
+ public static void dropShellPermission() {
+ getInstrumentation().getUiAutomation().dropShellPermissionIdentity();
+ }
+
+ public static int getPid(String packageName)
+ throws IOException, InterruptedException, TimeoutException {
+ UiDevice uiDevice = UiDevice.getInstance(getInstrumentation());
+ for (int i = 0; i < POLLING_TIMEOUT_MILLIS / POLLING_SLEEP_MILLIS; i++) {
+ String pid = uiDevice.executeShellCommand("pidof " + packageName).trim();
+ if (pid.length() > 0) {
+ return new Integer(pid);
+ }
+ Thread.sleep(POLLING_SLEEP_MILLIS);
+ }
+
+ throw new TimeoutException("Timed out waiting for pid");
+ }
+}
diff --git a/tests/test_app/LegacyTestApp.xml b/tests/test_app/LegacyTestApp.xml
new file mode 100644
index 0000000..4fe9761
--- /dev/null
+++ b/tests/test_app/LegacyTestApp.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.providers.media.testapp.legacy"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <uses-sdk android:minSdkVersion="30" android:targetSdkVersion="28" />
+
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+
+ <application android:label="LegacyTestApp"
+ android:requestLegacyExternalStorage="true">
+ <activity android:name="com.android.providers.media.util.TestAppActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
\ No newline at end of file
diff --git a/tests/test_app/TestAppForPermissionActivity.xml b/tests/test_app/TestAppForPermissionActivity.xml
new file mode 100644
index 0000000..cd1cc82
--- /dev/null
+++ b/tests/test_app/TestAppForPermissionActivity.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.providers.media.testapp.permission"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <uses-sdk android:minSdkVersion="30" android:targetSdkVersion="30" />
+
+ <uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION"/>
+ <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.MANAGE_MEDIA"/>
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+
+ <application android:label="TestAppPerms">
+ <activity android:name="com.android.providers.media.util.TestAppActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
\ No newline at end of file
diff --git a/tests/test_app/TestAppWithStoragePerms.xml b/tests/test_app/TestAppWithStoragePerms.xml
new file mode 100644
index 0000000..5910280
--- /dev/null
+++ b/tests/test_app/TestAppWithStoragePerms.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.providers.media.testapp.withstorageperms"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <uses-sdk android:minSdkVersion="30" android:targetSdkVersion="30" />
+
+ <uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION"/>
+ <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.MANAGE_MEDIA"/>
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+
+ <application android:label="TestAppPerms">
+ <activity android:name="com.android.providers.media.util.TestAppActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
\ No newline at end of file
diff --git a/tests/test_app/TestAppWithoutPerms.xml b/tests/test_app/TestAppWithoutPerms.xml
new file mode 100644
index 0000000..9708129
--- /dev/null
+++ b/tests/test_app/TestAppWithoutPerms.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.providers.media.testapp.withoutperms"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <uses-sdk android:minSdkVersion="30" android:targetSdkVersion="30" />
+
+ <application android:label="TestAppWithoutPerms">
+ <activity android:name="com.android.providers.media.util.TestAppActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
\ No newline at end of file
diff --git a/tests/test_app/src/com/android/providers/media/util/TestAppActivity.java b/tests/test_app/src/com/android/providers/media/util/TestAppActivity.java
new file mode 100644
index 0000000..8c95cce
--- /dev/null
+++ b/tests/test_app/src/com/android/providers/media/util/TestAppActivity.java
@@ -0,0 +1,41 @@
+/*
+ * 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.util;
+
+import static com.android.providers.media.util.TestUtils.QUERY_TYPE;
+import static com.android.providers.media.util.TestUtils.RUN_INFINITE_ACTIVITY;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+
+public class TestAppActivity extends Activity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ String queryType = getIntent().getStringExtra(QUERY_TYPE);
+ queryType = queryType == null ? "null" : queryType;
+
+ switch (queryType) {
+ case RUN_INFINITE_ACTIVITY:
+ while (true) {
+ }
+ default:
+ throw new IllegalStateException(
+ "Unknown query received from launcher app: " + queryType);
+ }
+ }
+}
diff --git a/tests/transcode/src/com/android/providers/media/transcode/TranscodeTest.java b/tests/transcode/src/com/android/providers/media/transcode/TranscodeTest.java
new file mode 100644
index 0000000..a77fd55
--- /dev/null
+++ b/tests/transcode/src/com/android/providers/media/transcode/TranscodeTest.java
@@ -0,0 +1,898 @@
+/*
+ * Copyright (C) 2020 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.transcode;
+
+import static androidx.test.InstrumentationRegistry.getContext;
+
+import static com.android.providers.media.transcode.TranscodeTestUtils.assertFileContent;
+import static com.android.providers.media.transcode.TranscodeTestUtils.assertTranscode;
+import static com.android.providers.media.transcode.TranscodeTestUtils.installAppWithStoragePermissions;
+import static com.android.providers.media.transcode.TranscodeTestUtils.open;
+import static com.android.providers.media.transcode.TranscodeTestUtils.openFileAs;
+import static com.android.providers.media.transcode.TranscodeTestUtils.uninstallApp;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.Manifest;
+import android.media.ApplicationMediaCapabilities;
+import android.media.MediaFormat;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.ParcelFileDescriptor;
+import android.os.SystemProperties;
+import android.provider.MediaStore;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.cts.install.lib.TestApp;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+
+import org.junit.After;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class TranscodeTest {
+ private static final File EXTERNAL_STORAGE_DIRECTORY
+ = Environment.getExternalStorageDirectory();
+ private static final File DIR_CAMERA
+ = new File(EXTERNAL_STORAGE_DIRECTORY, Environment.DIRECTORY_DCIM + "/Camera");
+ // TODO(b/169546642): Test other directories like /sdcard and /sdcard/foo
+ // These are the only transcode unsupported directories we can stage files in given our
+ // test app permissions
+ private static final File[] DIRS_NO_TRANSCODE = {
+ new File(EXTERNAL_STORAGE_DIRECTORY, Environment.DIRECTORY_PICTURES),
+ new File(EXTERNAL_STORAGE_DIRECTORY, Environment.DIRECTORY_MOVIES),
+ new File(EXTERNAL_STORAGE_DIRECTORY, Environment.DIRECTORY_DOWNLOADS),
+ new File(EXTERNAL_STORAGE_DIRECTORY, Environment.DIRECTORY_DCIM),
+ new File(EXTERNAL_STORAGE_DIRECTORY, Environment.DIRECTORY_DOCUMENTS),
+ };
+
+ static final String NONCE = String.valueOf(System.nanoTime());
+ private static final String HEVC_FILE_NAME = "TranscodeTestHEVC_" + NONCE + ".mp4";
+ private static final String SMALL_HEVC_FILE_NAME = "TranscodeTestHevcSmall_" + NONCE + ".mp4";
+ private static final String LEGACY_FILE_NAME = "TranscodeTestLegacy_" + NONCE + ".mp4";
+
+ private static final TestApp TEST_APP_HEVC = new TestApp("TestAppHevc",
+ "com.android.providers.media.transcode.testapp", 1, false,
+ "TranscodeTestAppSupportsHevc.apk");
+
+ private static final TestApp TEST_APP_SLOW_MOTION = new TestApp("TestAppSlowMotion",
+ "com.android.providers.media.transcode.testapp", 1, false,
+ "TranscodeTestAppSupportsSlowMotion.apk");
+
+ @Before
+ public void setUp() throws Exception {
+ Assume.assumeTrue(SystemProperties.getBoolean("sys.fuse.transcode_enabled", false));
+
+ TranscodeTestUtils.pollForExternalStorageState();
+ TranscodeTestUtils.grantPermission(getContext().getPackageName(),
+ Manifest.permission.READ_EXTERNAL_STORAGE);
+ TranscodeTestUtils.pollForPermission(Manifest.permission.READ_EXTERNAL_STORAGE, true);
+ TranscodeTestUtils.enableSeamlessTranscoding();
+ TranscodeTestUtils.disableTranscodingForAllPackages();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ TranscodeTestUtils.disableSeamlessTranscoding();
+ }
+
+ /**
+ * Tests that we return FD of transcoded file for legacy apps
+ * @throws Exception
+ */
+ @Test
+ public void testTranscoded_FilePath() throws Exception {
+ File modernFile = new File(DIR_CAMERA, HEVC_FILE_NAME);
+ try {
+ TranscodeTestUtils.stageHEVCVideoFile(modernFile);
+
+ ParcelFileDescriptor pfdOriginal = open(modernFile, false);
+
+ TranscodeTestUtils.enableTranscodingForPackage(getContext().getPackageName());
+ ParcelFileDescriptor pfdTranscoded = open(modernFile, false);
+
+ assertFileContent(modernFile, modernFile, pfdOriginal, pfdTranscoded, false);
+ } finally {
+ modernFile.delete();
+ }
+ }
+
+ /**
+ * Tests that we don't transcode files outside DCIM/Camera
+ * @throws Exception
+ */
+ @Test
+ public void testNoTranscodeOutsideCamera_FilePath() throws Exception {
+ File modernFile = new File(DIR_CAMERA, HEVC_FILE_NAME);
+ List<File> noTranscodeFiles = new ArrayList<>();
+ for (File file : DIRS_NO_TRANSCODE) {
+ noTranscodeFiles.add(new File(file, HEVC_FILE_NAME));
+ }
+ noTranscodeFiles.add(new File(getContext().getExternalFilesDir(null), HEVC_FILE_NAME));
+
+ try {
+ TranscodeTestUtils.stageHEVCVideoFile(modernFile);
+ for (File file : noTranscodeFiles) {
+ TranscodeTestUtils.stageHEVCVideoFile(file);
+ }
+ ParcelFileDescriptor pfdOriginal1 = open(modernFile, false);
+
+ TranscodeTestUtils.enableTranscodingForPackage(getContext().getPackageName());
+
+ for (File file : noTranscodeFiles) {
+ pfdOriginal1.seekTo(0);
+ ParcelFileDescriptor pfdOriginal2 = open(file, false);
+ assertFileContent(modernFile, file, pfdOriginal1, pfdOriginal2, true);
+ }
+ } finally {
+ modernFile.delete();
+ for (File file : noTranscodeFiles) {
+ file.delete();
+ }
+ }
+ }
+
+ /**
+ * Tests that same transcoded file is used for multiple open() from same app
+ * @throws Exception
+ */
+ @Test
+ public void testSameTranscoded_FilePath() throws Exception {
+ File modernFile = new File(DIR_CAMERA, HEVC_FILE_NAME);
+ try {
+ TranscodeTestUtils.stageHEVCVideoFile(modernFile);
+
+ TranscodeTestUtils.enableTranscodingForPackage(getContext().getPackageName());
+ ParcelFileDescriptor pfdTranscoded1 = open(modernFile, false);
+ ParcelFileDescriptor pfdTranscoded2 = open(modernFile, false);
+
+ assertFileContent(modernFile, modernFile, pfdTranscoded1, pfdTranscoded2, true);
+ } finally {
+ modernFile.delete();
+ }
+ }
+
+ /**
+ * Tests that we return FD of transcoded file for legacy apps
+ * @throws Exception
+ */
+ @Test
+ public void testTranscoded_ContentResolver() throws Exception {
+ File modernFile = new File(DIR_CAMERA, HEVC_FILE_NAME);
+ try {
+ Uri uri = TranscodeTestUtils.stageHEVCVideoFile(modernFile);
+
+ ParcelFileDescriptor pfdOriginal = open(uri, false, null /* bundle */);
+
+ TranscodeTestUtils.enableTranscodingForPackage(getContext().getPackageName());
+
+ ParcelFileDescriptor pfdTranscoded = open(uri, false, null /* bundle */);
+
+ assertFileContent(modernFile, modernFile, pfdOriginal, pfdTranscoded, false);
+ } finally {
+ modernFile.delete();
+ }
+ }
+
+ /**
+ * Tests that we don't transcode files outside DCIM/Camera
+ * @throws Exception
+ */
+ @Test
+ public void testNoTranscodeOutsideCamera_ConentResolver() throws Exception {
+ File modernFile = new File(DIR_CAMERA, HEVC_FILE_NAME);
+ List<File> noTranscodeFiles = new ArrayList<>();
+ for (File file : DIRS_NO_TRANSCODE) {
+ noTranscodeFiles.add(new File(file, HEVC_FILE_NAME));
+ }
+
+ try {
+ Uri uri = TranscodeTestUtils.stageHEVCVideoFile(modernFile);
+ ArrayList<Uri> noTranscodeUris = new ArrayList<>();
+ for (File file : noTranscodeFiles) {
+ noTranscodeUris.add(TranscodeTestUtils.stageHEVCVideoFile(file));
+ }
+
+ ParcelFileDescriptor pfdOriginal1 = open(uri, false, null /* bundle */);
+
+ TranscodeTestUtils.enableTranscodingForPackage(getContext().getPackageName());
+
+ for (int i = 0; i < noTranscodeUris.size(); i++) {
+ pfdOriginal1.seekTo(0);
+ ParcelFileDescriptor pfdOriginal2 =
+ open(noTranscodeUris.get(i), false, null /* bundle */);
+ assertFileContent(modernFile, noTranscodeFiles.get(1), pfdOriginal1, pfdOriginal2,
+ true);
+ }
+ } finally {
+ modernFile.delete();
+ for (File file : noTranscodeFiles) {
+ file.delete();
+ }
+ }
+ }
+
+ /**
+ * Tests that same transcoded file is used for multiple open() from same app
+ * @throws Exception
+ */
+ @Test
+ public void testSameTranscodedFile_ContentResolver() throws Exception {
+ File modernFile = new File(DIR_CAMERA, HEVC_FILE_NAME);
+ try {
+ Uri uri = TranscodeTestUtils.stageHEVCVideoFile(modernFile);
+
+ TranscodeTestUtils.enableTranscodingForPackage(getContext().getPackageName());
+
+ ParcelFileDescriptor pfdTranscoded1 = open(uri, false, null /* bundle */);
+ ParcelFileDescriptor pfdTranscoded2 = open(uri, false, null /* bundle */);
+
+ assertFileContent(modernFile, modernFile, pfdTranscoded1, pfdTranscoded2, true);
+ } finally {
+ modernFile.delete();
+ }
+ }
+
+ /**
+ * Tests that deletes are visible across legacy and modern apps
+ * @throws Exception
+ */
+ @Test
+ public void testDeleteTranscodedFile_FilePath() throws Exception {
+ File modernFile = new File(DIR_CAMERA, HEVC_FILE_NAME);
+ try {
+ TranscodeTestUtils.stageHEVCVideoFile(modernFile);
+
+ TranscodeTestUtils.enableTranscodingForPackage(getContext().getPackageName());
+
+ assertTrue(modernFile.delete());
+ assertFalse(modernFile.exists());
+
+ TranscodeTestUtils.disableTranscodingForAllPackages();
+
+ assertFalse(modernFile.exists());
+ } finally {
+ modernFile.delete();
+ }
+ }
+
+ /**
+ * Tests that renames are visible across legacy and modern apps
+ * @throws Exception
+ */
+ @Test
+ public void testRenameTranscodedFile_FilePath() throws Exception {
+ File modernFile = new File(DIR_CAMERA, HEVC_FILE_NAME);
+ File destFile = new File(DIR_CAMERA, "renamed_" + HEVC_FILE_NAME);
+ try {
+ TranscodeTestUtils.stageHEVCVideoFile(modernFile);
+
+ TranscodeTestUtils.enableTranscodingForPackage(getContext().getPackageName());
+
+ assertTrue(modernFile.renameTo(destFile));
+ assertTrue(destFile.exists());
+ assertFalse(modernFile.exists());
+
+ TranscodeTestUtils.disableTranscodingForAllPackages();
+
+ assertTrue(destFile.exists());
+ assertFalse(modernFile.exists());
+ } finally {
+ modernFile.delete();
+ destFile.delete();
+ }
+ }
+
+ /**
+ * Tests that transcode doesn't start until read(2)
+ * @throws Exception
+ */
+ @Test
+ public void testLazyTranscodedFile_FilePath() throws Exception {
+ File modernFile = new File(DIR_CAMERA, HEVC_FILE_NAME);
+ try {
+ TranscodeTestUtils.stageHEVCVideoFile(modernFile);
+
+ assertTranscode(modernFile, false);
+
+ TranscodeTestUtils.enableTranscodingForPackage(getContext().getPackageName());
+
+ assertTranscode(modernFile, true);
+ } finally {
+ modernFile.delete();
+ }
+ }
+
+ /**
+ * Tests that transcode cache is reused after file path transcode
+ * @throws Exception
+ */
+ @Test
+ public void testTranscodedCacheReuse_FilePath() throws Exception {
+ File modernFile = new File(DIR_CAMERA, HEVC_FILE_NAME);
+ try {
+ TranscodeTestUtils.stageHEVCVideoFile(modernFile);
+ TranscodeTestUtils.enableTranscodingForPackage(getContext().getPackageName());
+
+ assertTranscode(modernFile, true);
+ assertTranscode(modernFile, false);
+ } finally {
+ modernFile.delete();
+ }
+ }
+
+ /**
+ * Tests that transcode cache is reused after ContentResolver transcode
+ * @throws Exception
+ */
+ @Test
+ public void testTranscodedCacheReuse_ContentResolver() throws Exception {
+ File modernFile = new File(DIR_CAMERA, HEVC_FILE_NAME);
+ try {
+ Uri uri = TranscodeTestUtils.stageHEVCVideoFile(modernFile);
+ TranscodeTestUtils.enableTranscodingForPackage(getContext().getPackageName());
+
+ assertTranscode(uri, true);
+ assertTranscode(uri, false);
+ } finally {
+ modernFile.delete();
+ }
+ }
+
+ /**
+ * Tests that transcode cache is reused after ContentResolver transcode
+ * and file path opens
+ * @throws Exception
+ */
+ @Test
+ public void testTranscodedCacheReuse_ContentResolverFilePath() throws Exception {
+ File modernFile = new File(DIR_CAMERA, HEVC_FILE_NAME);
+ try {
+ Uri uri = TranscodeTestUtils.stageHEVCVideoFile(modernFile);
+ TranscodeTestUtils.enableTranscodingForPackage(getContext().getPackageName());
+
+ assertTranscode(uri, true);
+ assertTranscode(modernFile, false);
+ } finally {
+ modernFile.delete();
+ }
+ }
+
+ /**
+ * Tests that transcode cache is reused after file path transcode
+ * and ContentResolver opens
+ * @throws Exception
+ */
+ @Test
+ public void testTranscodedCacheReuse_FilePathContentResolver() throws Exception {
+ File modernFile = new File(DIR_CAMERA, HEVC_FILE_NAME);
+ try {
+ Uri uri = TranscodeTestUtils.stageHEVCVideoFile(modernFile);
+ TranscodeTestUtils.enableTranscodingForPackage(getContext().getPackageName());
+
+ assertTranscode(modernFile, true);
+ assertTranscode(uri, false);
+ } finally {
+ modernFile.delete();
+ }
+ }
+
+ /**
+ * Tests that transcode cache is reused after rename
+ * @throws Exception
+ */
+ @Test
+ public void testTranscodedCacheReuseAfterRename_FilePath() throws Exception {
+ File modernFile = new File(DIR_CAMERA, HEVC_FILE_NAME);
+ File destFile = new File(DIR_CAMERA, "renamed_" + HEVC_FILE_NAME);
+ try {
+ TranscodeTestUtils.stageHEVCVideoFile(modernFile);
+ TranscodeTestUtils.enableTranscodingForPackage(getContext().getPackageName());
+
+ assertTranscode(modernFile, true);
+
+ assertTrue(modernFile.renameTo(destFile));
+
+ assertTranscode(destFile, false);
+ } finally {
+ modernFile.delete();
+ destFile.delete();
+ }
+ }
+
+ @Test
+ public void testExtraAcceptOriginalFormatTrue_ContentResolver() throws Exception {
+ File modernFile = new File(DIR_CAMERA, HEVC_FILE_NAME);
+ try {
+ Uri uri = TranscodeTestUtils.stageHEVCVideoFile(modernFile);
+
+ ParcelFileDescriptor pfdOriginal1 = open(uri, false, null /* bundle */);
+
+ TranscodeTestUtils.enableTranscodingForPackage(getContext().getPackageName());
+
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(MediaStore.EXTRA_ACCEPT_ORIGINAL_MEDIA_FORMAT, true);
+ ParcelFileDescriptor pfdOriginal2 = open(uri, false, bundle);
+
+ assertFileContent(modernFile, modernFile, pfdOriginal1, pfdOriginal2, true);
+ } finally {
+ modernFile.delete();
+ }
+ }
+
+ @Test
+ public void testExtraAcceptOriginalFormatFalse_ContentResolver() throws Exception {
+ File modernFile = new File(DIR_CAMERA, HEVC_FILE_NAME);
+ try {
+ Uri uri = TranscodeTestUtils.stageHEVCVideoFile(modernFile);
+
+ ParcelFileDescriptor pfdOriginal = open(uri, false, null /* bundle */);
+
+ TranscodeTestUtils.enableTranscodingForPackage(getContext().getPackageName());
+
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(MediaStore.EXTRA_ACCEPT_ORIGINAL_MEDIA_FORMAT, false);
+ ParcelFileDescriptor pfdTranscoded = open(uri, false, bundle);
+
+ assertFileContent(modernFile, modernFile, pfdOriginal, pfdTranscoded, false);
+ } finally {
+ modernFile.delete();
+ }
+ }
+
+ @Test
+ public void testExtraMediaCapabilitiesHevcSupportedTrue_ContentResolver() throws Exception {
+ File modernFile = new File(DIR_CAMERA, HEVC_FILE_NAME);
+ try {
+ Uri uri = TranscodeTestUtils.stageHEVCVideoFile(modernFile);
+
+ ParcelFileDescriptor pfdOriginal1 = open(uri, false, null /* bundle */);
+
+ TranscodeTestUtils.enableTranscodingForPackage(getContext().getPackageName());
+
+ Bundle bundle = new Bundle();
+ ApplicationMediaCapabilities capabilities =
+ new ApplicationMediaCapabilities.Builder()
+ .addSupportedVideoMimeType(MediaFormat.MIMETYPE_VIDEO_HEVC).build();
+ bundle.putParcelable(MediaStore.EXTRA_MEDIA_CAPABILITIES, capabilities);
+ ParcelFileDescriptor pfdOriginal2 = open(uri, false, bundle);
+
+ assertFileContent(modernFile, modernFile, pfdOriginal1, pfdOriginal2, true);
+ } finally {
+ modernFile.delete();
+ }
+ }
+
+ @Test
+ public void testExtraMediaCapabilitiesHevcUnsupportedFalse_ContentResolver() throws Exception {
+ File modernFile = new File(DIR_CAMERA, HEVC_FILE_NAME);
+ try {
+ Uri uri = TranscodeTestUtils.stageHEVCVideoFile(modernFile);
+
+ ParcelFileDescriptor pfdOriginal1 = open(uri, false, null /* bundle */);
+
+ TranscodeTestUtils.enableTranscodingForPackage(getContext().getPackageName());
+
+ Bundle bundle = new Bundle();
+ ApplicationMediaCapabilities capabilities =
+ new ApplicationMediaCapabilities.Builder()
+ .addUnsupportedVideoMimeType(MediaFormat.MIMETYPE_VIDEO_HEVC).build();
+ bundle.putParcelable(MediaStore.EXTRA_MEDIA_CAPABILITIES, capabilities);
+ ParcelFileDescriptor pfdOriginal2 = open(uri, false, bundle);
+
+ assertFileContent(modernFile, modernFile, pfdOriginal1, pfdOriginal2, false);
+ } finally {
+ modernFile.delete();
+ }
+ }
+
+ @Test
+ public void testExtraMediaCapabilitiesHevcUnspecifiedFalse_ContentResolver() throws Exception {
+ File modernFile = new File(DIR_CAMERA, HEVC_FILE_NAME);
+ try {
+ Uri uri = TranscodeTestUtils.stageHEVCVideoFile(modernFile);
+
+ ParcelFileDescriptor pfdOriginal1 = open(uri, false, null /* bundle */);
+
+ TranscodeTestUtils.enableTranscodingForPackage(getContext().getPackageName());
+
+ Bundle bundle = new Bundle();
+ ApplicationMediaCapabilities capabilities =
+ new ApplicationMediaCapabilities.Builder().build();
+ bundle.putParcelable(MediaStore.EXTRA_MEDIA_CAPABILITIES, capabilities);
+ ParcelFileDescriptor pfdTranscoded = open(uri, false, bundle);
+
+ assertFileContent(modernFile, modernFile, pfdOriginal1, pfdTranscoded, false);
+ } finally {
+ modernFile.delete();
+ }
+ }
+
+ @Test
+ public void testExtraAcceptOriginalTrueAndMediaCapabilitiesHevcFalse_ContentResolver()
+ throws Exception {
+ File modernFile = new File(DIR_CAMERA, HEVC_FILE_NAME);
+ try {
+ Uri uri = TranscodeTestUtils.stageHEVCVideoFile(modernFile);
+
+ ParcelFileDescriptor pfdOriginal1 = open(uri, false, null /* bundle */);
+
+ TranscodeTestUtils.enableTranscodingForPackage(getContext().getPackageName());
+
+ Bundle bundle = new Bundle();
+ ApplicationMediaCapabilities capabilities =
+ new ApplicationMediaCapabilities.Builder().build();
+ bundle.putParcelable(MediaStore.EXTRA_MEDIA_CAPABILITIES, capabilities);
+ bundle.putBoolean(MediaStore.EXTRA_ACCEPT_ORIGINAL_MEDIA_FORMAT, true);
+ ParcelFileDescriptor pfdOriginal2 = open(uri, false, bundle);
+
+ assertFileContent(modernFile, modernFile, pfdOriginal1, pfdOriginal2, true);
+ } finally {
+ modernFile.delete();
+ }
+ }
+
+ @Test
+ public void testMediaCapabilitiesManifestHevc()
+ throws Exception {
+ File modernFile = new File(DIR_CAMERA, HEVC_FILE_NAME);
+ ParcelFileDescriptor pfdOriginal2 = null;
+ try {
+ installAppWithStoragePermissions(TEST_APP_HEVC);
+
+ Uri uri = TranscodeTestUtils.stageHEVCVideoFile(modernFile);
+
+ ParcelFileDescriptor pfdOriginal1 = open(modernFile, false);
+
+ TranscodeTestUtils.enableTranscodingForPackage(TEST_APP_HEVC.getPackageName());
+
+ pfdOriginal2 = openFileAs(TEST_APP_HEVC, modernFile);
+
+ assertFileContent(modernFile, modernFile, pfdOriginal1, pfdOriginal2, true);
+ } finally {
+ // Explicitly close PFD otherwise instrumention might crash when test_app is uninstalled
+ if (pfdOriginal2 != null) {
+ pfdOriginal2.close();
+ }
+ modernFile.delete();
+ uninstallApp(TEST_APP_HEVC);
+ }
+ }
+
+ @Test
+ public void testMediaCapabilitiesManifestSlowMotion()
+ throws Exception {
+ File modernFile = new File(DIR_CAMERA, HEVC_FILE_NAME);
+ ParcelFileDescriptor pfdOriginal2 = null;
+ try {
+ installAppWithStoragePermissions(TEST_APP_SLOW_MOTION);
+
+ Uri uri = TranscodeTestUtils.stageHEVCVideoFile(modernFile);
+
+ ParcelFileDescriptor pfdOriginal1 = open(modernFile, false);
+
+ TranscodeTestUtils.enableTranscodingForPackage(TEST_APP_SLOW_MOTION.getPackageName());
+
+ pfdOriginal2 = openFileAs(TEST_APP_SLOW_MOTION, modernFile);
+
+ assertFileContent(modernFile, modernFile, pfdOriginal1, pfdOriginal2, false);
+ } finally {
+ // Explicitly close PFD otherwise instrumention might crash when test_app is uninstalled
+ if (pfdOriginal2 != null) {
+ pfdOriginal2.close();
+ }
+ modernFile.delete();
+ uninstallApp(TEST_APP_HEVC);
+ }
+ }
+
+ @Test
+ public void testAppCompatNoTranscodeHevc() throws Exception {
+ File modernFile = new File(DIR_CAMERA, HEVC_FILE_NAME);
+ String packageName = TEST_APP_SLOW_MOTION.getPackageName();
+ ParcelFileDescriptor pfdOriginal2 = null;
+ try {
+ installAppWithStoragePermissions(TEST_APP_SLOW_MOTION);
+
+ Uri uri = TranscodeTestUtils.stageHEVCVideoFile(modernFile);
+
+ ParcelFileDescriptor pfdOriginal1 = open(modernFile, false);
+
+ TranscodeTestUtils.enableTranscodingForPackage(packageName);
+ // App compat takes precedence
+ TranscodeTestUtils.forceEnableAppCompatHevc(packageName);
+
+ Thread.sleep(2000);
+
+ pfdOriginal2 = openFileAs(TEST_APP_SLOW_MOTION, modernFile);
+
+ assertFileContent(modernFile, modernFile, pfdOriginal1, pfdOriginal2, true);
+ } finally {
+ // Explicitly close PFD otherwise instrumention might crash when test_app is uninstalled
+ if (pfdOriginal2 != null) {
+ pfdOriginal2.close();
+ }
+ modernFile.delete();
+ TranscodeTestUtils.resetAppCompat(packageName);
+ uninstallApp(TEST_APP_HEVC);
+ }
+ }
+
+ @Test
+ public void testAppCompatTranscodeHevc() throws Exception {
+ File modernFile = new File(DIR_CAMERA, HEVC_FILE_NAME);
+ String packageName = TEST_APP_SLOW_MOTION.getPackageName();
+ ParcelFileDescriptor pfdOriginal2 = null;
+ try {
+ installAppWithStoragePermissions(TEST_APP_SLOW_MOTION);
+
+ Uri uri = TranscodeTestUtils.stageHEVCVideoFile(modernFile);
+
+ ParcelFileDescriptor pfdOriginal1 = open(modernFile, false);
+
+ // Transcoding is disabled but app compat enables it (disables hevc support)
+ TranscodeTestUtils.forceDisableAppCompatHevc(packageName);
+
+ pfdOriginal2 = openFileAs(TEST_APP_SLOW_MOTION, modernFile);
+
+ assertFileContent(modernFile, modernFile, pfdOriginal1, pfdOriginal2, false);
+ } finally {
+ // Explicitly close PFD otherwise instrumention might crash when test_app is uninstalled
+ if (pfdOriginal2 != null) {
+ pfdOriginal2.close();
+ }
+ modernFile.delete();
+ TranscodeTestUtils.resetAppCompat(packageName);
+ uninstallApp(TEST_APP_HEVC);
+ }
+ }
+
+ /**
+ * Tests that we never initiate tanscoding for legacy formats.
+ * This test compares the bytes read before and after enabling transcoding for the test app.
+ * @throws Exception
+ */
+ @Test
+ public void testTranscodedNotInitiatedForLegacy_UsingBytesRead() throws Exception {
+ File legacyFile = new File(DIR_CAMERA, LEGACY_FILE_NAME);
+ try {
+ TranscodeTestUtils.stageLegacyVideoFile(legacyFile);
+
+ ParcelFileDescriptor pfdOriginal = open(legacyFile, false);
+
+ TranscodeTestUtils.enableTranscodingForPackage(getContext().getPackageName());
+ ParcelFileDescriptor pfdTranscoded = open(legacyFile, false);
+
+ assertFileContent(legacyFile, legacyFile, pfdOriginal, pfdTranscoded, true);
+ } finally {
+ legacyFile.delete();
+ }
+ }
+
+ /**
+ * Tests that we never initiate tanscoding for legacy formats.
+ * This test asserts using the time it took to read after enabling transcoding for the test app.
+ * The reason for keeping this check separately (than
+ * {@link TranscodeTest#testTranscodedNotInitiatedForLegacy_UsingTiming()}) is that this
+ * provides a higher level of suret that the timing wasn't favorable because of any caching
+ * after open().
+ * @throws Exception
+ */
+ @Test
+ public void testTranscodedNotInitiatedForLegacy_UsingTiming() throws Exception {
+ File legacyFile = new File(DIR_CAMERA, LEGACY_FILE_NAME);
+ try {
+ TranscodeTestUtils.stageLegacyVideoFile(legacyFile);
+ TranscodeTestUtils.enableTranscodingForPackage(getContext().getPackageName());
+
+ assertTranscode(legacyFile, false);
+ } finally {
+ legacyFile.delete();
+ }
+ }
+
+ /**
+ * Tests that we don't timeout while transcoding small HEVC videos.
+ * For instance, due to some calculation errors we might incorrectly make timeout to be 0.
+ * We test this by making sure that a small HEVC video (< 1 sec long and < 1Mb size) gets
+ * transcoded.
+ * @throws Exception
+ */
+ @Test
+ public void testNoTranscodeTimeoutForSmallHevcVideos() throws Exception {
+ File modernFile = new File(DIR_CAMERA, SMALL_HEVC_FILE_NAME);
+ try {
+ TranscodeTestUtils.stageSmallHevcVideoFile(modernFile);
+ ParcelFileDescriptor pfdOriginal = open(modernFile, false);
+
+ TranscodeTestUtils.enableTranscodingForPackage(getContext().getPackageName());
+ ParcelFileDescriptor pfdTranscoded = open(modernFile, false);
+
+ assertFileContent(modernFile, modernFile, pfdOriginal, pfdTranscoded, false);
+ } finally {
+ modernFile.delete();
+ }
+ }
+
+ /**
+ * Tests that we transcode an HEVC file when a modern app passes the mediaCapabilitiesUid of a
+ * legacy app that cannot handle an HEVC file.
+ */
+ @Test
+ public void testOriginalCallingUid_modernAppPassLegacyAppUid()
+ throws Exception {
+ File modernFile = new File(DIR_CAMERA, HEVC_FILE_NAME);
+ ParcelFileDescriptor pfdModernApp = null;
+ ParcelFileDescriptor pfdModernAppPassingLegacyUid = null;
+ try {
+ installAppWithStoragePermissions(TEST_APP_SLOW_MOTION);
+ Uri uri = TranscodeTestUtils.stageHEVCVideoFile(modernFile);
+
+ // pfdModernApp is for original content (without transcoding) since this is a modern
+ // app.
+ pfdModernApp = open(modernFile, false);
+
+ // pfdModernAppPassingLegacyUid is for transcoded content since this modern app is
+ // passing the UID of a legacy app capable of handling HEVC files.
+ Bundle bundle = new Bundle();
+ bundle.putInt(MediaStore.EXTRA_MEDIA_CAPABILITIES_UID,
+ getContext().getPackageManager().getPackageUid(
+ TEST_APP_SLOW_MOTION.getPackageName(), 0));
+ pfdModernAppPassingLegacyUid = open(uri, false, bundle);
+
+ assertTranscode(pfdModernApp, false);
+ assertTranscode(pfdModernAppPassingLegacyUid, true);
+
+ // pfdModernApp and pfdModernAppPassingLegacyUid should be different.
+ assertFileContent(modernFile, modernFile, pfdModernApp, pfdModernAppPassingLegacyUid,
+ false);
+ } finally {
+ if (pfdModernApp != null) {
+ pfdModernApp.close();
+ }
+
+ if (pfdModernAppPassingLegacyUid != null) {
+ pfdModernAppPassingLegacyUid.close();
+ }
+ modernFile.delete();
+ uninstallApp(TEST_APP_SLOW_MOTION);
+ }
+ }
+
+ /**
+ * Tests that we don't transcode an HEVC file when a legacy app passes the mediaCapabilitiesUid
+ * of a modern app that can handle an HEVC file.
+ */
+ @Test
+ public void testOriginalCallingUid_legacyAppPassModernAppUid()
+ throws Exception {
+ File modernFile = new File(DIR_CAMERA, HEVC_FILE_NAME);
+ ParcelFileDescriptor pfdLegacyApp = null;
+ ParcelFileDescriptor pfdLegacyAppPassingModernUid = null;
+ try {
+ installAppWithStoragePermissions(TEST_APP_HEVC);
+ Uri uri = TranscodeTestUtils.stageHEVCVideoFile(modernFile);
+
+ // pfdLegacyApp is for transcoded content since this is a legacy app.
+ TranscodeTestUtils.enableTranscodingForPackage(getContext().getPackageName());
+ pfdLegacyApp = open(modernFile, false);
+
+ // pfdLegacyAppPassingModernUid is for original content (without transcoding) since this
+ // legacy app is passing the UID of a modern app capable of handling HEVC files.
+ Bundle bundle = new Bundle();
+ bundle.putInt(MediaStore.EXTRA_MEDIA_CAPABILITIES_UID,
+ getContext().getPackageManager().getPackageUid(TEST_APP_HEVC.getPackageName(),
+ 0));
+ pfdLegacyAppPassingModernUid = open(uri, false, bundle);
+
+ assertTranscode(pfdLegacyApp, true);
+ assertTranscode(pfdLegacyAppPassingModernUid, false);
+
+ // pfdLegacyApp and pfdLegacyAppPassingModernUid should be different.
+ assertFileContent(modernFile, modernFile, pfdLegacyApp, pfdLegacyAppPassingModernUid,
+ false);
+ } finally {
+ if (pfdLegacyApp != null) {
+ pfdLegacyApp.close();
+ }
+
+ if (pfdLegacyAppPassingModernUid != null) {
+ pfdLegacyAppPassingModernUid.close();
+ }
+ modernFile.delete();
+ uninstallApp(TEST_APP_HEVC);
+ }
+ }
+
+ /**
+ * Tests that we return FD of original file from
+ * MediaStore#getOriginalMediaFormatFileDescriptor.
+ * @throws Exception
+ */
+ @Test
+ public void testGetOriginalMediaFormatFileDescriptor_returnsOriginalFileDescriptor()
+ throws Exception {
+ File modernFile = new File(DIR_CAMERA, HEVC_FILE_NAME);
+ try {
+ TranscodeTestUtils.stageHEVCVideoFile(modernFile);
+
+ ParcelFileDescriptor pfdOriginal = open(modernFile, false);
+
+ TranscodeTestUtils.enableTranscodingForPackage(getContext().getPackageName());
+ ParcelFileDescriptor pfdTranscoded = open(modernFile, false);
+
+ ParcelFileDescriptor pfdOriginalMediaFormat =
+ MediaStore.getOriginalMediaFormatFileDescriptor(getContext(), pfdTranscoded);
+
+ assertFileContent(modernFile, modernFile, pfdOriginal, pfdOriginalMediaFormat, true);
+ assertFileContent(modernFile, modernFile, pfdTranscoded, pfdOriginalMediaFormat, false);
+ } finally {
+ modernFile.delete();
+ }
+ }
+
+ /**
+ * Tests that we can successfully write to a transcoded file.
+ * We check this by writing something to tanscoded content and then read it back.
+ */
+ @Test
+ public void testWriteSuccessfulToTranscodedContent() throws Exception {
+ File modernFile = new File(DIR_CAMERA, HEVC_FILE_NAME);
+ ParcelFileDescriptor pfdTranscodedContent = null;
+ try {
+ TranscodeTestUtils.stageHEVCVideoFile(modernFile);
+ TranscodeTestUtils.enableTranscodingForPackage(getContext().getPackageName());
+ pfdTranscodedContent = open(modernFile, false);
+
+ // read some bytes from some random offset
+ Random random = new Random(System.currentTimeMillis());
+ int byteCount = 512;
+ int fileOffset = random.nextInt((int) pfdTranscodedContent.getStatSize() - byteCount);
+ byte[] readBytes = TranscodeTestUtils.read(pfdTranscodedContent, byteCount, fileOffset);
+
+ // write the bytes at the same offset after some modification
+ pfdTranscodedContent = open(modernFile, true);
+ byte[] writeBytes = new byte[byteCount];
+ for (int i = 0; i < byteCount; ++i) {
+ writeBytes[i] = (byte) ~readBytes[i];
+ }
+ TranscodeTestUtils.write(pfdTranscodedContent, writeBytes, byteCount, fileOffset);
+
+ // read back the same number of bytes from the same offset
+ readBytes = TranscodeTestUtils.read(pfdTranscodedContent, byteCount, fileOffset);
+
+ // assert that read is same as written
+ assertTrue(Arrays.equals(readBytes, writeBytes));
+ } finally {
+ if (pfdTranscodedContent != null) {
+ pfdTranscodedContent.close();
+ }
+ modernFile.delete();
+ }
+ }
+}
diff --git a/tools/dialogs/Android.bp b/tools/dialogs/Android.bp
index 8d2c000..d0ccff2 100644
--- a/tools/dialogs/Android.bp
+++ b/tools/dialogs/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "packages_providers_MediaProvider_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["packages_providers_MediaProvider_license"],
+}
+
android_app {
name: "MediaProviderDialogsTool",
manifest: "AndroidManifest.xml",
diff --git a/tools/dialogs/AndroidManifest.xml b/tools/dialogs/AndroidManifest.xml
index 947f1bd..960cb13 100644
--- a/tools/dialogs/AndroidManifest.xml
+++ b/tools/dialogs/AndroidManifest.xml
@@ -1,14 +1,18 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.providers.media.tools.dialogs">
+<?xml version="1.0" encoding="utf-8"?>
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.providers.media.tools.dialogs">
+
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.MANAGE_MEDIA"/>
<application android:label="DialogsTool">
- <activity android:name=".DialogsActivity">
+ <activity android:name=".DialogsActivity"
+ android:exported="true">
<intent-filter android:label="DialogsTool">
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tools/dialogs/src/com/android/providers/media/tools/dialogs/DialogsActivity.java b/tools/dialogs/src/com/android/providers/media/tools/dialogs/DialogsActivity.java
index 4ff1731..867bfaf 100644
--- a/tools/dialogs/src/com/android/providers/media/tools/dialogs/DialogsActivity.java
+++ b/tools/dialogs/src/com/android/providers/media/tools/dialogs/DialogsActivity.java
@@ -99,6 +99,14 @@
addAction("Request delete", () -> {
return MediaStore.createDeleteRequest(getContentResolver(), mRequestItems.get());
});
+ addAction("Request favorite", () -> {
+ return MediaStore.createFavoriteRequest(getContentResolver(), mRequestItems.get(),
+ true);
+ });
+ addAction("Request unfavorite", () -> {
+ return MediaStore.createFavoriteRequest(getContentResolver(), mRequestItems.get(),
+ false);
+ });
new BackgroundTask().execute();
}
diff --git a/transcode.sh b/transcode.sh
new file mode 100644
index 0000000..c223eb5
--- /dev/null
+++ b/transcode.sh
@@ -0,0 +1,18 @@
+# For extracting a transcode_compat_manifest from a csv file in the format
+# package_name,hevc_support,slow_motion_support,hdr_10_support,hdr_10_plus_support,hdr_hlg_support,hdr_dolby_vision_support,hevc_support_shift,slow_motion_support_shift,hdr_10_support_shift,hd_10_plus_support_shift,hdr_hlg_support_shift,hdr_dolby_vision_support_shift,media_capability
+# com.foo,1,0,0,0,0,0,1,0,0,0,0,0,1
+# ....
+function transcode_compat_manifest() {
+ # Cat file
+ # Remove CLRF (DOS format)
+ # Remove first line (header)
+ # Extract first and last columns in each line
+ # For device_config convert new lines (\n) to comma(,)
+ # For device_config remove trailing comma(,)
+ case "$1" in
+ -r) cat $2 | tr -d '\r' | sed 1d | awk -F "," '{new_var=$1","$NF; print new_var}';;
+ -d) cat $2 | tr -d '\r' | sed 1d | awk -F "," '{new_var=$1","$NF; print new_var}' | tr '\n' ',' | sed 's/,$//g';;
+ *) "Enter '-d' for device_config, '-r' for resource";;
+ esac
+ echo
+}