Merge branch 'dev/11/fp3/security-aosp-rvc-release' into int/11/fp3
* dev/11/fp3/security-aosp-rvc-release:
Fix path traversal vulnerabilities in MediaProvider
Canonicalize file path for insertion by legacy apps
Remove invalid surrogates during bindSelection
Change-Id: I9581c7e5c1889e93f4fc068a2eff6bc5d43c4d0a
diff --git a/jni/FuseDaemon.cpp b/jni/FuseDaemon.cpp
index e927fd1..52ac5f7 100644
--- a/jni/FuseDaemon.cpp
+++ b/jni/FuseDaemon.cpp
@@ -427,10 +427,14 @@
// invalidate node_name if different case
// Note that we invalidate async otherwise we will deadlock the kernel
if (name != node->GetName()) {
- std::thread t([=]() {
- fuse_inval(fuse->se, fuse->ToInode(parent), fuse->ToInode(node), node->GetName(),
- path);
- });
+ // 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
+ // up invalidating the wrong inode but that shouldn't result in correctness issues.
+ const fuse_ino_t parent_ino = fuse->ToInode(parent);
+ const fuse_ino_t child_ino = fuse->ToInode(node);
+ const std::string& node_name = node->GetName();
+
+ std::thread t([=]() { fuse_inval(fuse->se, parent_ino, child_ino, node_name, path); });
t.detach();
}
}
@@ -1485,7 +1489,7 @@
return;
}
const string path = node->BuildPath();
- if (!is_app_accessible_path(fuse->mp, path, req->ctx.uid)) {
+ if (path != "/storage/emulated" && !is_app_accessible_path(fuse->mp, path, req->ctx.uid)) {
fuse_reply_err(req, ENOENT);
return;
}
@@ -1509,6 +1513,13 @@
bool for_write = mask & W_OK;
bool is_directory = S_ISDIR(stat.st_mode);
if (is_directory) {
+ if (path == "/storage/emulated" && mask == X_OK) {
+ // Special case for this path: apps should be allowed to enter it,
+ // but not list directory contents (which would be user numbers).
+ int res = access(path.c_str(), X_OK);
+ fuse_reply_err(req, res ? errno : 0);
+ return;
+ }
status = fuse->mp->IsOpendirAllowed(path, req->ctx.uid, for_write);
} else {
if (mask & X_OK) {
diff --git a/jni/node-inl.h b/jni/node-inl.h
index d6ad0ad..364a327 100644
--- a/jni/node-inl.h
+++ b/jni/node-inl.h
@@ -19,12 +19,16 @@
#include <android-base/logging.h>
+#include <cstdint>
+#include <limits>
#include <list>
#include <memory>
#include <mutex>
+#include <set>
#include <sstream>
#include <string>
#include <unordered_set>
+#include <utility>
#include <vector>
#include "libfuse_jni/ReaddirHelper.h"
@@ -175,14 +179,18 @@
node* LookupChildByName(const std::string& name, bool acquire) const {
std::lock_guard<std::recursive_mutex> guard(*lock_);
- const char* name_char = name.c_str();
- for (node* child : children_) {
- const std::string& child_name = child->GetName();
- if (!strcasecmp(name_char, child_name.c_str()) && !child->deleted_) {
+ // 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_) {
if (acquire) {
child->Acquire();
}
-
return child;
}
}
@@ -201,10 +209,41 @@
void Rename(const std::string& name, node* new_parent) {
std::lock_guard<std::recursive_mutex> guard(*lock_);
- name_ = name;
if (new_parent != parent_) {
RemoveFromParent();
+ name_ = name;
AddToParent(new_parent);
+ return;
+ }
+
+ // Changing name_ will change the expected position of this node in parent's set of
+ // children. Consider following scenario:
+ // 1. This node: "b"; parent's set: {"a", "b", "c"}
+ // 2. Rename("b", "d")
+ //
+ // After rename, parent's set should become: {"a", "b", "d"}, but if we simply change the
+ // name it will be {"a", "d", "b"}, which violates properties of the set.
+ //
+ // To make sure that parent's set is always valid, changing name is 3 steps procedure:
+ // 1. Remove this node from parent's set.
+ // 2 Change the name.
+ // 3. Add it back to the set.
+ // Rename of node without changing its parent. Still need to remove and re-add it to make
+ // sure lookup index is correct.
+ if (name_ != name) {
+ // If this is a root node, simply rename it.
+ if (parent_ == nullptr) {
+ name_ = name;
+ return;
+ }
+
+ auto it = parent_->children_.find(this);
+ CHECK(it != parent_->children_.end());
+ parent_->children_.erase(it);
+
+ name_ = name;
+
+ parent_->children_.insert(this);
}
}
@@ -299,7 +338,7 @@
CHECK(parent != nullptr);
parent_ = parent;
- parent_->children_.push_back(this);
+ parent_->children_.insert(this);
// TODO(narayan, zezeozue): It's unclear why we need to call Acquire on the
// parent node when we're adding a child to it.
@@ -311,16 +350,55 @@
std::lock_guard<std::recursive_mutex> guard(*lock_);
if (parent_ != nullptr) {
- std::list<node*>& children = parent_->children_;
- std::list<node*>::iterator it = std::find(children.begin(), children.end(), this);
+ auto it = parent_->children_.find(this);
+ CHECK(it != parent_->children_.end());
+ parent_->children_.erase(it);
- CHECK(it != children.end());
- children.erase(it);
parent_->Release(1);
parent_ = nullptr;
}
}
+ // A custom heterogeneous comparator used for set of this node's children_ to speed up child
+ // node by name lookups.
+ //
+ // This comparator treats node* as pair (node->name_, node): two nodes* are first
+ // compared by their name using case-insenstive comparison function. If their names are equal,
+ // then pointers are compared as integers.
+ //
+ // See LookupChildByName function to see how this comparator is used.
+ //
+ // Note that it's important to first compare by name_, since it will make all nodes with same
+ // name (compared using strcasecmp) together, which allows LookupChildByName function to find
+ // range of the candidate nodes by issuing two binary searches.
+ struct NodeCompare {
+ using is_transparent = void;
+
+ bool operator()(const node* lhs, const node* rhs) const {
+ int cmp = strcasecmp(lhs->name_.c_str(), rhs->name_.c_str());
+ if (cmp != 0) {
+ return cmp < 0;
+ }
+ return reinterpret_cast<uintptr_t>(lhs) < reinterpret_cast<uintptr_t>(rhs);
+ }
+
+ bool operator()(const node* lhs, const std::pair<std::string, uintptr_t>& rhs) const {
+ int cmp = strcasecmp(lhs->name_.c_str(), rhs.first.c_str());
+ if (cmp != 0) {
+ return cmp < 0;
+ }
+ return reinterpret_cast<uintptr_t>(lhs) < rhs.second;
+ }
+
+ bool operator()(const std::pair<std::string, uintptr_t>& lhs, const node* rhs) const {
+ int cmp = strcasecmp(lhs.first.c_str(), rhs->name_.c_str());
+ if (cmp != 0) {
+ return cmp < 0;
+ }
+ return lhs.second < reinterpret_cast<uintptr_t>(rhs);
+ }
+ };
+
// A helper function to recursively construct the absolute path of a given node.
// If |safe| is true, builds a PII safe path instead
void BuildPathForNodeRecursive(bool safe, const node* node, std::stringstream* path) const;
@@ -329,9 +407,9 @@
std::string name_;
// The reference count for this node. Guarded by |lock_|.
uint32_t refcount_;
- // List of children of this node. All of them contain a back reference
+ // Set of children of this node. All of them contain a back reference
// to their parent. Guarded by |lock_|.
- std::list<node*> children_;
+ std::set<node*, NodeCompare> children_;
// Containing directory for this node. Guarded by |lock_|.
node* parent_;
// List of file handles associated with this node. Guarded by |lock_|.
diff --git a/jni/node_test.cpp b/jni/node_test.cpp
index 098bb28..357cea8 100644
--- a/jni/node_test.cpp
+++ b/jni/node_test.cpp
@@ -3,6 +3,7 @@
#include "node-inl.h"
#include <algorithm>
+#include <limits>
#include <memory>
#include <mutex>
@@ -33,6 +34,9 @@
unique_node_ptr CreateNode(node* parent, const std::string& path) {
return unique_node_ptr(node::Create(parent, path, &lock_, &tracker_), &NodeTest::destroy);
}
+
+ // Expose NodeCompare for testing.
+ node::NodeCompare cmp;
};
TEST_F(NodeTest, TestCreate) {
@@ -239,3 +243,78 @@
ASSERT_EQ(mixed_child.get(), lower_child);
ASSERT_EQ(mixed_child.get(), upper_child);
}
+
+TEST_F(NodeTest, RenameSameNameSameParent) {
+ unique_node_ptr parent = CreateNode(nullptr, "/path1");
+ unique_node_ptr child = CreateNode(parent.get(), "subdir");
+
+ ASSERT_EQ(child.get(), parent->LookupChildByName("SuBdIr", false /* acquire */));
+ ASSERT_EQ(2, GetRefCount(parent.get()));
+
+ child->Rename("subdir", parent.get());
+
+ ASSERT_EQ(child.get(), parent->LookupChildByName("SuBdIr", false /* acquire */));
+ ASSERT_EQ(2, GetRefCount(parent.get()));
+}
+
+TEST_F(NodeTest, RenameRoot) {
+ unique_node_ptr root = CreateNode(nullptr, "/root");
+ ASSERT_EQ(1, GetRefCount(root.get()));
+
+ root->Rename("/i-am-root!", nullptr);
+
+ ASSERT_EQ("/i-am-root!", root->GetName());
+ ASSERT_EQ(1, GetRefCount(root.get()));
+}
+
+TEST_F(NodeTest, NodeCompareDefinesLinearOrder) {
+ unique_node_ptr node_a = CreateNode(nullptr, "a");
+ unique_node_ptr node_b = CreateNode(nullptr, "B");
+ unique_node_ptr node_c = CreateNode(nullptr, "c");
+
+ ASSERT_FALSE(cmp.operator()(node_a.get(), node_a.get()));
+ ASSERT_FALSE(cmp.operator()(node_b.get(), node_b.get()));
+ ASSERT_FALSE(cmp.operator()(node_c.get(), node_c.get()));
+
+ auto check_fn = [&](const node* lhs_node, const node* rhs_node) {
+ ASSERT_TRUE(cmp.operator()(lhs_node, rhs_node));
+ ASSERT_FALSE(cmp.operator()(rhs_node, lhs_node));
+ };
+
+ check_fn(node_a.get(), node_b.get());
+ check_fn(node_b.get(), node_c.get());
+ check_fn(node_a.get(), node_c.get());
+
+ // ("A", 0) < node_a < ("a", max_uintptr_t) < node_b
+ ASSERT_TRUE(cmp.operator()(std::make_pair("A", 0), node_a.get()));
+ ASSERT_TRUE(cmp.operator()(node_a.get(),
+ std::make_pair("A", std::numeric_limits<uintptr_t>::max())));
+ ASSERT_TRUE(cmp.operator()(std::make_pair("A", std::numeric_limits<uintptr_t>::max()),
+ node_b.get()));
+}
+
+TEST_F(NodeTest, LookupChildByName_ChildrenWithSameName) {
+ 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 bar1 = CreateNode(parent.get(), "BAR");
+ unique_node_ptr bar2 = CreateNode(parent.get(), "bar");
+ unique_node_ptr baz1 = CreateNode(parent.get(), "baZ");
+ unique_node_ptr baz2 = CreateNode(parent.get(), "Baz");
+
+ auto test_fn = [&](const std::string& name, node* first, node* second) {
+ auto node1 = parent->LookupChildByName(name, false /* acquire */);
+ ASSERT_EQ(std::min(first, second), node1);
+ node1->SetDeleted();
+
+ auto node2 = parent->LookupChildByName(name, false /* acquire */);
+ ASSERT_EQ(std::max(first, second), node2);
+ node2->SetDeleted();
+
+ ASSERT_EQ(nullptr, parent->LookupChildByName(name, false /* acquire */));
+ };
+
+ test_fn("foo", foo1.get(), foo2.get());
+ test_fn("bAr", bar1.get(), bar2.get());
+ test_fn("BaZ", baz1.get(), baz2.get());
+}
diff --git a/legacy/src/com/android/providers/media/LegacyMediaProvider.java b/legacy/src/com/android/providers/media/LegacyMediaProvider.java
index 6e152d4..e921155 100644
--- a/legacy/src/com/android/providers/media/LegacyMediaProvider.java
+++ b/legacy/src/com/android/providers/media/LegacyMediaProvider.java
@@ -26,6 +26,7 @@
import android.content.ContentValues;
import android.content.Context;
import android.content.OperationApplicationException;
+import android.content.UriMatcher;
import android.content.pm.ProviderInfo;
import android.database.Cursor;
import android.net.Uri;
@@ -99,9 +100,10 @@
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
+ final String appendedSelection = getAppendedSelection(selection, uri);
final DatabaseHelper helper = getDatabaseForUri(uri);
return helper.runWithoutTransaction((db) -> {
- return db.query("files", projection, selection, selectionArgs,
+ return db.query(getTableName(uri), projection, appendedSelection, selectionArgs,
null, null, sortOrder);
});
}
@@ -151,7 +153,7 @@
final DatabaseHelper helper = getDatabaseForUri(uri);
final long id = helper.runWithTransaction((db) -> {
- return db.insert("files", null, values);
+ return db.insert(getTableName(uri), null, values);
});
return ContentUris.withAppendedId(uri, id);
}
@@ -166,6 +168,48 @@
throw new UnsupportedOperationException();
}
+ private static final int AUDIO_PLAYLISTS_ID_MEMBERS = 112;
+ private static final int FILES_ID = 701;
+ private static final UriMatcher BASIC_URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
+ static {
+ final UriMatcher basicUriMatcher = BASIC_URI_MATCHER;
+ basicUriMatcher.addURI(MediaStore.AUTHORITY_LEGACY, "*/audio/playlists/#/members",
+ AUDIO_PLAYLISTS_ID_MEMBERS);
+ basicUriMatcher.addURI(MediaStore.AUTHORITY_LEGACY, "*/file/#", FILES_ID);
+ };
+
+ private static String getAppendedSelection(String selection, Uri uri) {
+ String whereClause = "";
+ final int match = BASIC_URI_MATCHER.match(uri);
+ switch (match) {
+ case AUDIO_PLAYLISTS_ID_MEMBERS:
+ whereClause = "playlist_id=" + uri.getPathSegments().get(3);
+ break;
+ case FILES_ID:
+ whereClause = "_id=" + uri.getPathSegments().get(2);
+ break;
+ default:
+ // No additional whereClause required
+ }
+ if (selection == null || selection.isEmpty()) {
+ return whereClause;
+ } else if (whereClause.isEmpty()) {
+ return selection;
+ } else {
+ return whereClause + " AND " + selection;
+ }
+ }
+
+ private static String getTableName(Uri uri) {
+ final int playlistMatch = BASIC_URI_MATCHER.match(uri);
+ if (playlistMatch == AUDIO_PLAYLISTS_ID_MEMBERS) {
+ return "audio_playlists_map";
+ } else {
+ // Return the "files" table by default for all other Uris.
+ return "files";
+ }
+ }
+
@Override
public Bundle call(String authority, String method, String arg, Bundle extras) {
switch (method) {
diff --git a/res/drawable/ic_warning.xml b/res/drawable/ic_delete.xml
similarity index 82%
rename from res/drawable/ic_warning.xml
rename to res/drawable/ic_delete.xml
index 2163203..333cb63 100644
--- a/res/drawable/ic_warning.xml
+++ b/res/drawable/ic_delete.xml
@@ -20,6 +20,6 @@
android:viewportHeight="24"
android:viewportWidth="24">
<path
- android:fillColor="#1A73E8"
- android:pathData="M12 5.99L19.53 19H4.47L12 5.99M12 2L1 21h22L12 2zm1 14h-2v2h2v-2zm0-6h-2v4h2v-4z" />
+ android:fillColor="@color/clear_cache_icon_color"
+ android:pathData="M15 4V3H9v1H4v2h1v13c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V6h1V4h-5zm2 15H7V6h10v13zM9 8h2v9H9zm4 0h2v9h-2z" />
</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_warning.xml b/res/drawable/thumb_clip_gradient.xml
similarity index 64%
copy from res/drawable/ic_warning.xml
copy to res/drawable/thumb_clip_gradient.xml
index 2163203..d94b0c2 100644
--- a/res/drawable/ic_warning.xml
+++ b/res/drawable/thumb_clip_gradient.xml
@@ -14,12 +14,8 @@
limitations under the License.
-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportHeight="24"
- android:viewportWidth="24">
- <path
- android:fillColor="#1A73E8"
- android:pathData="M12 5.99L19.53 19H4.47L12 5.99M12 2L1 21h22L12 2zm1 14h-2v2h2v-2zm0-6h-2v4h2v-4z" />
-</vector>
\ No newline at end of file
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@color/thumb_more_tint"/>
+ <corners android:radius="4dp" />
+</shape>
diff --git a/res/layout/cache_clearing_dialog.xml b/res/layout/cache_clearing_dialog.xml
index 06f97b8..bf5a60b 100644
--- a/res/layout/cache_clearing_dialog.xml
+++ b/res/layout/cache_clearing_dialog.xml
@@ -20,15 +20,18 @@
android:theme="@style/CacheClearingAlertDialogTheme"
android:paddingStart="?android:attr/dialogPreferredPadding"
android:paddingEnd="?android:attr/dialogPreferredPadding"
+ android:paddingTop="@dimen/dialog_space"
+ android:paddingBottom="10dp"
android:orientation="vertical">
<ImageView
android:adjustViewBounds="true"
+ android:id="@+id/dialog_icon"
android:layout_gravity="bottom|center_horizontal"
android:layout_width="24dp"
android:layout_height="24dp"
- android:layout_marginTop="20dp"
+ android:layout_marginBottom="7dp"
android:scaleType="fitCenter"
- android:src="@drawable/ic_warning"
+ android:src="@drawable/ic_delete"
android:contentDescription="@null"/>
<TextView
diff --git a/res/layout/permission_body.xml b/res/layout/permission_body.xml
index 6282c7c..0fb4ece 100644
--- a/res/layout/permission_body.xml
+++ b/res/layout/permission_body.xml
@@ -61,8 +61,13 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/thumb_clip"
- android:scaleType="centerCrop"
- android:tint="@color/thumb_more_tint" />
+ android:scaleType="centerCrop"/>
+ <View
+ android:id="@+id/thumb_more_gradient"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@drawable/thumb_clip_gradient"
+ android:visibility="gone"/>
<TextView
android:id="@+id/thumb_more_text"
android:layout_width="match_parent"
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 99778ca..09a1296 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">Plus <xliff:g id="COUNT_1">^1</xliff:g> bykomende items</item>
<item quantity="one">Plus <xliff:g id="COUNT_0">^1</xliff:g> bykomende item</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Vee tydelike programlêers uit?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Vee tydelike programlêers uit"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> wil \'n paar tydelike lêers uitvee. Dit kan verhoogde batterygebruik of sellulêre data tot gevolg hê."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Vee tans tydelike programlêers uit …"</string>
+ <string name="clear" msgid="5524638938415865915">"Vee uit"</string>
<string name="allow" msgid="8885707816848569619">"Laat toe"</string>
<string name="deny" msgid="6040983710442068936">"Weier"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index f8400b6..1a62bf5 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -37,9 +37,10 @@
<item quantity="one">እንዲሁም <xliff:g id="COUNT_1">^1</xliff:g> ተጨማሪ ንጥሎች</item>
<item quantity="other">እንዲሁም <xliff:g id="COUNT_1">^1</xliff:g> ተጨማሪ ንጥሎች</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"ጊዜያዊ የመተግበሪያ ፋይሎች ይጽዱ?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"ጊዜያዊ የመተግበሪያ ፋይሎች ይጸዱ?"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> አንዳንድ ጊዜያዊ ፋይሎችን ማጽዳት ይፈልጋል። ይህ የበለጠ የባትሪ ኃይል ወይም የተንቀሳቃሽ ስልክ ውሂብ ፍጆታን ሊጨምር ይችላል።"</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"ጊዜያዊ የመተግበሪያ ፋይሎችን በማጽዳት ላይ…"</string>
+ <string name="clear" msgid="5524638938415865915">"አጽዳ"</string>
<string name="allow" msgid="8885707816848569619">"ፍቀድ"</string>
<string name="deny" msgid="6040983710442068936">"ከልክል"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index dd3b567..c5d7cea 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -45,9 +45,10 @@
<item quantity="other">و<xliff:g id="COUNT_1">^1</xliff:g> عنصر إضافي</item>
<item quantity="one">وعنصر إضافي واحد (<xliff:g id="COUNT_0">^1</xliff:g>)</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"هل تريد محو ملفات التطبيق المؤقتة؟"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"محو ملفات التطبيق المؤقتة"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"يريد تطبيق <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> محو بعض الملفات المؤقتة. قد يؤدي هذا إلى زيادة استهلاك شحن البطارية أو بيانات شبكة الجوّال."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"جارٍ محو ملفات التطبيق المؤقتة…"</string>
+ <string name="clear" msgid="5524638938415865915">"محو"</string>
<string name="allow" msgid="8885707816848569619">"سماح"</string>
<string name="deny" msgid="6040983710442068936">"رفض"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index d6c697e..35449a8 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -21,7 +21,7 @@
<string name="app_label" msgid="9035307001052716210">"মিডিয়া সঞ্চয়াগাৰ"</string>
<string name="artist_label" msgid="8105600993099120273">"শিল্পী"</string>
<string name="unknown" msgid="2059049215682829375">"অজ্ঞাত"</string>
- <string name="root_images" msgid="5861633549189045666">"প্ৰতিচ্ছবিসমূহ"</string>
+ <string name="root_images" msgid="5861633549189045666">"Images"</string>
<string name="root_videos" msgid="8792703517064649453">"ভিডিঅ\'সমূহ"</string>
<string name="root_audio" msgid="3505830755201326018">"অডিঅ’"</string>
<string name="root_documents" msgid="3829103301363849237">"নথিপত্র"</string>
@@ -37,9 +37,10 @@
<item quantity="one">আৰু <xliff:g id="COUNT_1">^1</xliff:g> টা অতিৰিক্ত বস্তু</item>
<item quantity="other">আৰু <xliff:g id="COUNT_1">^1</xliff:g> টা অতিৰিক্ত বস্তু</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"অস্থায়ী এপ্ ফাইলসমূহ মচিবনে?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"অস্থায়ী এপ্ ফাইলসমূহ মচক"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>এ কিছুমান অস্থায়ী ফাইল মচিব বিচাৰিছে। ইয়াৰ ফলত বেটাৰী অথবা চেলুলাৰ ডেটাৰ ব্যৱহাৰ বৃদ্ধি হ’ব পাৰে।"</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"অস্থায়ী এপ্ ফাইলসমূহ মচি থকা হৈছে…"</string>
+ <string name="clear" msgid="5524638938415865915">"মচক"</string>
<string name="allow" msgid="8885707816848569619">"অনুমতি দিয়ক"</string>
<string name="deny" msgid="6040983710442068936">"অস্বীকাৰ কৰক"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 4a278d7..a8d2ab3 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">Üstəgəl <xliff:g id="COUNT_1">^1</xliff:g> əlavə element</item>
<item quantity="one">Üstəgəl <xliff:g id="COUNT_0">^1</xliff:g> əlavə element</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Müvəqqəti tətbiq faylları silinsin?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Müvəqqəti tətbiq fayllarını silin"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> bəzi müvəqqəti faylları silmək istəyir. Bu, batareya və ya mobil data istifadəsinin artmasına səbəb ola bilər."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Müvəqqəti tətbiq faylları silinir…"</string>
+ <string name="clear" msgid="5524638938415865915">"Silin"</string>
<string name="allow" msgid="8885707816848569619">"İcazə verin"</string>
<string name="deny" msgid="6040983710442068936">"Rədd edin"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 6a9a757..9756151 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -39,9 +39,10 @@
<item quantity="few">I još <xliff:g id="COUNT_1">^1</xliff:g> stavke</item>
<item quantity="other">I još <xliff:g id="COUNT_1">^1</xliff:g> stavki</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Želite li da obrišete privremene datoteke aplikacija?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Obrišite privremene datoteke aplikacija"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> želi da obriše neke privremene datoteke. Ovo može da dovede do povećane potrošnje baterije ili mobilnih podataka."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Brišu se privremene datoteke aplikacija…"</string>
+ <string name="clear" msgid="5524638938415865915">"Obriši"</string>
<string name="allow" msgid="8885707816848569619">"Dozvoli"</string>
<string name="deny" msgid="6040983710442068936">"Odbij"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 78175e3..58bffee 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -41,9 +41,10 @@
<item quantity="many">Плюс <xliff:g id="COUNT_1">^1</xliff:g> дадатковых элементаў</item>
<item quantity="other">Плюс <xliff:g id="COUNT_1">^1</xliff:g> дадатковага элемента</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Ачысціць часовыя файлы праграм?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Ачысціць часовыя файлы праграм"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> запытвае дазвол на выдаленне некаторых часовых файлаў. У сувязі з гэтым можа павялічыцца ўзровень выкарыстання акумулятара ці памер сотавай перадачы даных."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Выдаляюцца часовыя файлы праграм…"</string>
+ <string name="clear" msgid="5524638938415865915">"Ачысціць"</string>
<string name="allow" msgid="8885707816848569619">"Дазволіць"</string>
<string name="deny" msgid="6040983710442068936">"Адмовіць"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index c52ece9..b576228 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">И още <xliff:g id="COUNT_1">^1</xliff:g> допълнителни елемента</item>
<item quantity="one">И още <xliff:g id="COUNT_0">^1</xliff:g> допълнителен елемент</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Да се изчистят ли временните файлове на приложенията?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Изчистване на временните файлове на приложенията"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> иска да изчисти някои временни файлове. Това може да доведе до увеличено използване на батерията или мобилните данни."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Временните файлове на приложенията се изчистват…"</string>
+ <string name="clear" msgid="5524638938415865915">"Изчистване"</string>
<string name="allow" msgid="8885707816848569619">"Разрешаване"</string>
<string name="deny" msgid="6040983710442068936">"Отказ"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 9f27ed3..4b02f68 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -21,7 +21,7 @@
<string name="app_label" msgid="9035307001052716210">"মিডিয়া স্টোরেজ"</string>
<string name="artist_label" msgid="8105600993099120273">"শিল্পী"</string>
<string name="unknown" msgid="2059049215682829375">"অজানা"</string>
- <string name="root_images" msgid="5861633549189045666">"ছবি"</string>
+ <string name="root_images" msgid="5861633549189045666">"Images"</string>
<string name="root_videos" msgid="8792703517064649453">"ভিডিও"</string>
<string name="root_audio" msgid="3505830755201326018">"অডিও"</string>
<string name="root_documents" msgid="3829103301363849237">"ডকুমেন্ট"</string>
@@ -37,9 +37,10 @@
<item quantity="one">এছাড়াও <xliff:g id="COUNT_1">^1</xliff:g>টি অতিরিক্ত আইটেম</item>
<item quantity="other">এছাড়াও <xliff:g id="COUNT_1">^1</xliff:g>টি অতিরিক্ত আইটেম</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"অস্থায়ী অ্যাপ ফাইল মুছে দিতে চান?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"অস্থায়ী অ্যাপ ফাইলগুলি খালি করুন"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> কিছু অস্থায়ী ফাইলকে মুছে দিতে চায়। এর ফলে, ব্যাটারি বা মোবাইল ডেটা বেশি খরচ হতে পারে।"</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"অস্থায়ী অ্যাপ ফাইল মুছে ফেলা হচ্ছে…"</string>
+ <string name="clear" msgid="5524638938415865915">"সরান"</string>
<string name="allow" msgid="8885707816848569619">"অনুমতি দিন"</string>
<string name="deny" msgid="6040983710442068936">"বাতিল করুন"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index e40f5f7..9f89481 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -39,9 +39,10 @@
<item quantity="few">Još <xliff:g id="COUNT_1">^1</xliff:g> dodatne stavke</item>
<item quantity="other">Još <xliff:g id="COUNT_1">^1</xliff:g> dodatnih stavki</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Obrisati privremene fajlove aplikacija?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Brisanje privremenih fajlova aplikacija"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"Aplikacija <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> želi obrisati neke privremene fajlove. Ovo može dovesti do povećanog korištenja baterije ili prijenosa podataka na mobilnoj mreži."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Brisanje privremenih fajlova aplikacije…"</string>
+ <string name="clear" msgid="5524638938415865915">"Obriši"</string>
<string name="allow" msgid="8885707816848569619">"Dozvoli"</string>
<string name="deny" msgid="6040983710442068936">"Odbij"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 1a0069b..184a9b9 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other"><xliff:g id="COUNT_1">^1</xliff:g> elements addicionals més</item>
<item quantity="one"><xliff:g id="COUNT_0">^1</xliff:g> element addicional més</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Vols esborrar els fitxers temporals d\'aplicacions?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Esborra fitxers temporals d\'aplicacions"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vol esborrar alguns fitxers temporals. Això pot suposar un augment de l\'ús de la bateria o de les dades mòbils."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"S\'estan esborrant els fitxers temporals d\'aplicacions…"</string>
+ <string name="clear" msgid="5524638938415865915">"Esborra"</string>
<string name="allow" msgid="8885707816848569619">"Permet"</string>
<string name="deny" msgid="6040983710442068936">"Denega"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index e4c1bc0..3fa3e40 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -41,9 +41,10 @@
<item quantity="other">Plus <xliff:g id="COUNT_1">^1</xliff:g> dalších položek</item>
<item quantity="one">Plus <xliff:g id="COUNT_0">^1</xliff:g> další položka</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Vymazat dočasné soubory aplikací?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Vymazání dočasných souborů aplikací"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"Aplikace <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> chce vymazat nějaké dočasné soubory. Tato akce může vést ke zvýšenému využití baterie nebo mobilních dat."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Mazání dočasných souborů aplikace…"</string>
+ <string name="clear" msgid="5524638938415865915">"Vymazat"</string>
<string name="allow" msgid="8885707816848569619">"Povolit"</string>
<string name="deny" msgid="6040983710442068936">"Zakázat"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 074233c..96ee522 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -37,9 +37,10 @@
<item quantity="one">Plus <xliff:g id="COUNT_1">^1</xliff:g> andet element</item>
<item quantity="other">Plus <xliff:g id="COUNT_1">^1</xliff:g> andre elementer</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Vil du rydde midlertidige appfiler?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Ryd midlertidige appfiler"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vil gerne rydde nogle midlertidige filer. Dette kan resultere i øget forbrug af batteri eller mobildata."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Rydder midlertidige appfiler…"</string>
+ <string name="clear" msgid="5524638938415865915">"Ryd"</string>
<string name="allow" msgid="8885707816848569619">"Tillad"</string>
<string name="deny" msgid="6040983710442068936">"Afvis"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 1dbc776..8b19ff5 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other"><xliff:g id="COUNT_1">^1</xliff:g> weitere Elemente</item>
<item quantity="one"><xliff:g id="COUNT_0">^1</xliff:g> weiteres Element</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Temporäre App-Dateien löschen?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Temporäre App-Dateien löschen"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> möchte einige temporäre Dateien löschen. Dadurch können Akkuverbrauch und mobile Datennutzung steigen."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Temporäre App-Dateien werden gelöscht…"</string>
+ <string name="clear" msgid="5524638938415865915">"Löschen"</string>
<string name="allow" msgid="8885707816848569619">"Zulassen"</string>
<string name="deny" msgid="6040983710442068936">"Ablehnen"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 970e877..7045ca0 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">Συν <xliff:g id="COUNT_1">^1</xliff:g> επιπλέον στοιχεία</item>
<item quantity="one">Συν <xliff:g id="COUNT_0">^1</xliff:g> επιπλέον στοιχείο</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Να διαγραφούν τα προσωρινά αρχεία εφαρμογών;"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Διαγραφή προσωρινών αρχείων εφαρμογών"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"Η εφαρμογή <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> θέλει να διαγράψει ορισμένα προσωρινά αρχεία. Αυτό μπορεί να οδηγήσει σε αυξημένη χρήση μπαταριών ή δεδομένων κινητής τηλεφωνίας."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Διαγραφή προσωρινών αρχείων εφαρμογών…"</string>
+ <string name="clear" msgid="5524638938415865915">"Διαγραφή"</string>
<string name="allow" msgid="8885707816848569619">"Να επιτρέπεται"</string>
<string name="deny" msgid="6040983710442068936">"Απόρριψη"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 9f91376..1205a7e 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">Plus <xliff:g id="COUNT_1">^1</xliff:g> additional items</item>
<item quantity="one">Plus <xliff:g id="COUNT_0">^1</xliff:g> additional item</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Clear temporary app files?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Clear temporary app files"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> would like to clear some temporary files. This may result in an increased usage of battery or mobile data."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Clearing temporary app files…"</string>
+ <string name="clear" msgid="5524638938415865915">"Clear"</string>
<string name="allow" msgid="8885707816848569619">"Allow"</string>
<string name="deny" msgid="6040983710442068936">"Deny"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index 9f91376..1205a7e 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">Plus <xliff:g id="COUNT_1">^1</xliff:g> additional items</item>
<item quantity="one">Plus <xliff:g id="COUNT_0">^1</xliff:g> additional item</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Clear temporary app files?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Clear temporary app files"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> would like to clear some temporary files. This may result in an increased usage of battery or mobile data."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Clearing temporary app files…"</string>
+ <string name="clear" msgid="5524638938415865915">"Clear"</string>
<string name="allow" msgid="8885707816848569619">"Allow"</string>
<string name="deny" msgid="6040983710442068936">"Deny"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 9f91376..1205a7e 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">Plus <xliff:g id="COUNT_1">^1</xliff:g> additional items</item>
<item quantity="one">Plus <xliff:g id="COUNT_0">^1</xliff:g> additional item</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Clear temporary app files?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Clear temporary app files"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> would like to clear some temporary files. This may result in an increased usage of battery or mobile data."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Clearing temporary app files…"</string>
+ <string name="clear" msgid="5524638938415865915">"Clear"</string>
<string name="allow" msgid="8885707816848569619">"Allow"</string>
<string name="deny" msgid="6040983710442068936">"Deny"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 9f91376..1205a7e 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">Plus <xliff:g id="COUNT_1">^1</xliff:g> additional items</item>
<item quantity="one">Plus <xliff:g id="COUNT_0">^1</xliff:g> additional item</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Clear temporary app files?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Clear temporary app files"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> would like to clear some temporary files. This may result in an increased usage of battery or mobile data."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Clearing temporary app files…"</string>
+ <string name="clear" msgid="5524638938415865915">"Clear"</string>
<string name="allow" msgid="8885707816848569619">"Allow"</string>
<string name="deny" msgid="6040983710442068936">"Deny"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index 78226b4..18ba860 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">Plus <xliff:g id="COUNT_1">^1</xliff:g> additional items</item>
<item quantity="one">Plus <xliff:g id="COUNT_0">^1</xliff:g> additional item</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Clear temporary app files?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Clear temporary app files"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> would like to clear some temporary files. This may result in an increased usage of battery or cellular data."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Clearing temporary app files…"</string>
+ <string name="clear" msgid="5524638938415865915">"Clear"</string>
<string name="allow" msgid="8885707816848569619">"Allow"</string>
<string name="deny" msgid="6040983710442068936">"Deny"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 9ca1b9b..e2ffe99 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other"><xliff:g id="COUNT_1">^1</xliff:g> elementos adicionales</item>
<item quantity="one"><xliff:g id="COUNT_0">^1</xliff:g> elemento adicional</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"¿Deseas borrar archivos temporales de apps?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Borra archivos temporales de apps"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> quiere borrar algunos archivos temporales, lo que podría ocasionar un mayor uso de la batería o los datos móviles."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Borrando archivos temporales de apps…"</string>
+ <string name="clear" msgid="5524638938415865915">"Borrar"</string>
<string name="allow" msgid="8885707816848569619">"Permitir"</string>
<string name="deny" msgid="6040983710442068936">"Rechazar"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 7d54c38..7d0ee18 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">Y <xliff:g id="COUNT_1">^1</xliff:g> elementos más</item>
<item quantity="one">Y <xliff:g id="COUNT_0">^1</xliff:g> elemento más</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"¿Borrar archivos temporales de aplicaciones?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Borrar archivos de aplicaciones temporales"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> quiere borrar algunos archivos temporales. Esta acción puede aumentar el uso de la batería o los datos móviles."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Borrando archivos temporales de aplicaciones…"</string>
+ <string name="clear" msgid="5524638938415865915">"Borrar"</string>
<string name="allow" msgid="8885707816848569619">"Permitir"</string>
<string name="deny" msgid="6040983710442068936">"Denegar"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index fd66592..1dbfc5c 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">Veel <xliff:g id="COUNT_1">^1</xliff:g> lisaüksust</item>
<item quantity="one">Veel <xliff:g id="COUNT_0">^1</xliff:g> lisaüksus</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Kas soovite rakenduse ajutised failid kustutada?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Rakenduse ajutiste failide kustutamine"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> soovib kustutada mõned ajutised failid. See võib aku või mobiilse andmeside kasutust suurendada."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Rakenduse ajutiste failide kustutamine …"</string>
+ <string name="clear" msgid="5524638938415865915">"Kustuta"</string>
<string name="allow" msgid="8885707816848569619">"Luba"</string>
<string name="deny" msgid="6040983710442068936">"Keela"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 28a6d4f..982a7c8 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">Eta beste <xliff:g id="COUNT_1">^1</xliff:g> elementu</item>
<item quantity="one">Eta beste <xliff:g id="COUNT_0">^1</xliff:g> elementu</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Aplikazioen aldi baterako fitxategiak garbitu nahi dituzu?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Garbitu aplikazioen aldi baterako fitxategiak"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aplikazioak aldi baterako fitxategi batzuk ezabatu nahi ditu. Ondorioz, baliteke bateria edo datu-konexioko datu gehiago erabiltzea."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Aplikazioaren aldi baterako fitxategiak garbitzen…"</string>
+ <string name="clear" msgid="5524638938415865915">"Garbitu"</string>
<string name="allow" msgid="8885707816848569619">"Baimendu"</string>
<string name="deny" msgid="6040983710442068936">"Ukatu"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 622792d..fc0d11e 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -28,7 +28,7 @@
<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_deny" msgid="6190589471415815741">"رد کردن"</string>
+ <string name="grant_dialog_button_deny" msgid="6190589471415815741">"مجاز نبودن"</string>
<plurals name="permission_more_thumb" formatted="false" msgid="4392079224649478923">
<item quantity="one">+<xliff:g id="COUNT_1">^1</xliff:g></item>
<item quantity="other">+<xliff:g id="COUNT_1">^1</xliff:g></item>
@@ -37,11 +37,12 @@
<item quantity="one">بهعلاوه <xliff:g id="COUNT_1">^1</xliff:g> مورد دیگر</item>
<item quantity="other">بهعلاوه <xliff:g id="COUNT_1">^1</xliff:g> مورد دیگر</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"فایلهای موقت برنامه پاک شوند؟"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"پاک کردن فایلهای موقت برنامه"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> میخواهد برخی از فایلهای موقت را پاک کند. این کار ممکن است استفاده از باتری یا داده شبکه تلفن همراه را افزایش دهد."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"درحال پاک کردن فایلهای موقتی برنامه…"</string>
+ <string name="clear" msgid="5524638938415865915">"پاک کردن"</string>
<string name="allow" msgid="8885707816848569619">"اجازه دادن"</string>
- <string name="deny" msgid="6040983710442068936">"رد کردن"</string>
+ <string name="deny" msgid="6040983710442068936">"مجاز نبودن"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
<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>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 142b960..39517ba 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">Ja <xliff:g id="COUNT_1">^1</xliff:g> muuta asiaa</item>
<item quantity="one">Ja <xliff:g id="COUNT_0">^1</xliff:g> muu asia</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Poistetaanko väliaikaisia sovellustiedostoja?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Poista väliaikaisia sovellustiedostoja"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> haluaa poistaa joitain väliaikaisia tiedostoja. Tämä voi lisätä akun tai mobiilidatan käyttöä."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Poistetaan väliaikaisia sovellustiedostoja…"</string>
+ <string name="clear" msgid="5524638938415865915">"Poista"</string>
<string name="allow" msgid="8885707816848569619">"Salli"</string>
<string name="deny" msgid="6040983710442068936">"Estä"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 74e490d..021ba70 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -37,9 +37,10 @@
<item quantity="one">Plus <xliff:g id="COUNT_1">^1</xliff:g> élément supplémentaire</item>
<item quantity="other">Plus <xliff:g id="COUNT_1">^1</xliff:g> éléments supplémentaires</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Effacer les fichiers temporaires des applications?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Effacer les fichiers temporaires des applications"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aimerait supprimer certains fichiers temporaires. Ceci peut entraîner une utilisation accrue de la pile ou des données cellulaires."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Suppression des fichiers temporaires des applications en cours…"</string>
+ <string name="clear" msgid="5524638938415865915">"Effacer"</string>
<string name="allow" msgid="8885707816848569619">"Autoriser"</string>
<string name="deny" msgid="6040983710442068936">"Refuser"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index beace75..7b0d694 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -37,9 +37,10 @@
<item quantity="one">Plus <xliff:g id="COUNT_1">^1</xliff:g> autre élément</item>
<item quantity="other">Plus <xliff:g id="COUNT_1">^1</xliff:g> autres éléments</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Effacer les fichiers d\'application temporaires ?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Effacer les fichiers d\'application temporaires"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> souhaite supprimer quelques fichiers temporaires, ce qui risque de solliciter davantage la batterie et le réseau de données mobiles."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Suppression des fichiers d\'application temporaires…"</string>
+ <string name="clear" msgid="5524638938415865915">"Effacer"</string>
<string name="allow" msgid="8885707816848569619">"Autoriser"</string>
<string name="deny" msgid="6040983710442068936">"Refuser"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 05a69de..93e281d 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">E <xliff:g id="COUNT_1">^1</xliff:g> elementos adicionais</item>
<item quantity="one">E <xliff:g id="COUNT_0">^1</xliff:g> elemento adicional</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Queres borrar os ficheiros temporais da aplicación?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Borrar os ficheiros temporais das aplicacións"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> quere borrar algúns ficheiros temporais. Por este motivo, pode aumentar o uso da batería e dos datos móbiles."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Borrando ficheiros temporais das aplicacións…"</string>
+ <string name="clear" msgid="5524638938415865915">"Borrar"</string>
<string name="allow" msgid="8885707816848569619">"Permitir"</string>
<string name="deny" msgid="6040983710442068936">"Denegar"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 232fea0..d7cc37d 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -21,8 +21,8 @@
<string name="app_label" msgid="9035307001052716210">"મીડિયા સ્ટોરેજ"</string>
<string name="artist_label" msgid="8105600993099120273">"કલાકાર"</string>
<string name="unknown" msgid="2059049215682829375">"અજાણ"</string>
- <string name="root_images" msgid="5861633549189045666">"છબીઓ"</string>
- <string name="root_videos" msgid="8792703517064649453">"વિડિઓઝ"</string>
+ <string name="root_images" msgid="5861633549189045666">"Images"</string>
+ <string name="root_videos" msgid="8792703517064649453">"વીડિયો"</string>
<string name="root_audio" msgid="3505830755201326018">"ઑડિયો"</string>
<string name="root_documents" msgid="3829103301363849237">"દસ્તાવેજો"</string>
<string name="permission_required" msgid="1460820436132943754">"આ આઇટમમાં ફેરફાર કરવા માટે અથવા તેને ડિલીટ કરવા માટે પરવાનગી હોવી જરૂરી છે."</string>
@@ -37,9 +37,10 @@
<item quantity="one">ઉપરાંત <xliff:g id="COUNT_1">^1</xliff:g> વધારાની આઇટમ</item>
<item quantity="other">ઉપરાંત <xliff:g id="COUNT_1">^1</xliff:g> વધારાની આઇટમ</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"ઍપની બધી અસ્થાયી ફાઇલોને સાફ કરીએ?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"ઍપની બધી અસ્થાયી ફાઇલ સાફ કરો"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> કેટલીક અસ્થાયી ફાઇલોને સાફ કરવા માગે છે. આના પરિણામે બૅટરી અથવા સેલ્યુલર ડેટાના વપરાશમાં વધારો થઈ શકે છે."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"ઍપની બધી અસ્થાયી ફાઇલો સાફ કરી રહ્યાં છીએ…"</string>
+ <string name="clear" msgid="5524638938415865915">"સાફ કરો"</string>
<string name="allow" msgid="8885707816848569619">"મંજૂરી આપો"</string>
<string name="deny" msgid="6040983710442068936">"નકારો"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 2442f74..3937bd2 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -37,9 +37,10 @@
<item quantity="one">अन्य <xliff:g id="COUNT_1">^1</xliff:g> आइटम</item>
<item quantity="other">अन्य <xliff:g id="COUNT_1">^1</xliff:g> आइटम</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"ऐप्लिकेशन से जुड़ी, कुछ समय तक रहने वाली फ़ाइलें मिटाना चाहते हैं?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"ऐप्लिकेशन से जुड़ी, कुछ समय तक सेव रहने वाली फ़ाइलें मिटाएं"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> कुछ समय तक रहने वाली फ़ाइलें हटाना चाहता है. इससे बैटरी या मोबाइल डेटा का इस्तेमाल बढ़ सकता है."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"ऐप्लिकेशन से जुड़ी, कुछ समय तक सेव रहने वाली फ़ाइलें मिटाई जा रही हैं…"</string>
+ <string name="clear" msgid="5524638938415865915">"मिटाएं"</string>
<string name="allow" msgid="8885707816848569619">"अनुमति दें"</string>
<string name="deny" msgid="6040983710442068936">"अनुमति न दें"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 1025609..6b4abd9 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -39,9 +39,10 @@
<item quantity="few">Plus sljedeći broj dodatnih stavki: <xliff:g id="COUNT_1">^1</xliff:g></item>
<item quantity="other">Plus sljedeći broj dodatnih stavki: <xliff:g id="COUNT_1">^1</xliff:g></item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Želite li izbrisati privremene datoteke aplikacija?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Brisanje privremenih datoteka aplikacija"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> želi izbrisati neke privremene datoteke. Zbog toga može doći do veće upotrebe baterije ili mobilnih podataka."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Brišu se privremene datoteke aplikacija…"</string>
+ <string name="clear" msgid="5524638938415865915">"Izbriši"</string>
<string name="allow" msgid="8885707816848569619">"Dopusti"</string>
<string name="deny" msgid="6040983710442068936">"Odbij"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 89c12f5..1e39499 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">És további <xliff:g id="COUNT_1">^1</xliff:g> elem</item>
<item quantity="one">És további <xliff:g id="COUNT_0">^1</xliff:g> elem</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Törli az ideiglenes alkalmazásfájlokat?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Ideiglenes alkalmazásfájlok törlése"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"A(z) <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> szeretne törölni néhány ideiglenes fájlt. Ez nagyobb akkumulátor- és mobiladat-használatot eredményezhet."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Ideiglenes alkalmazásfájlok törlése…"</string>
+ <string name="clear" msgid="5524638938415865915">"Törlés"</string>
<string name="allow" msgid="8885707816848569619">"Engedélyezés"</string>
<string name="deny" msgid="6040983710442068936">"Tiltás"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 81f1fc4..862e27a 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -37,9 +37,10 @@
<item quantity="one">Ու ևս <xliff:g id="COUNT_1">^1</xliff:g> լրացուցիչ տարր</item>
<item quantity="other">Ու ևս <xliff:g id="COUNT_1">^1</xliff:g> լրացուցիչ տարր</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Ջնջե՞լ հավելվածի լրացուցիչ ֆայլերը"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Ջնջեք հավելվածի լրացուցիչ ֆայլերը"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> հավելվածը հայցում է որոշ ժամանակավոր ֆայլեր ջնջելու թույլտվություն։ Դրա համար կարող է օգտագործվել ավելի շատ մարտկոցի լիցք կամ բջջային ինտերնետ։"</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Հավելվածների ժամանակավոր ֆայլերը ջնջվում են…"</string>
+ <string name="clear" msgid="5524638938415865915">"Ջնջել"</string>
<string name="allow" msgid="8885707816848569619">"Թույլատրել"</string>
<string name="deny" msgid="6040983710442068936">"Մերժել"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index c5f0532..42406d7 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">Plus <xliff:g id="COUNT_1">^1</xliff:g> item tambahan</item>
<item quantity="one">Plus <xliff:g id="COUNT_0">^1</xliff:g> item tambahan</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Hapus file aplikasi sementara?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Menghapus file aplikasi sementara"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ingin menghapus beberapa file sementara. Ini dapat meningkatkan penggunaan baterai atau data seluler."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Menghapus file aplikasi sementara…"</string>
+ <string name="clear" msgid="5524638938415865915">"Hapus"</string>
<string name="allow" msgid="8885707816848569619">"Izinkan"</string>
<string name="deny" msgid="6040983710442068936">"Tolak"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 7c03eef..fb7daa3 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -37,9 +37,10 @@
<item quantity="one">Auk <xliff:g id="COUNT_1">^1</xliff:g> atriðis til viðbótar</item>
<item quantity="other">Auk <xliff:g id="COUNT_1">^1</xliff:g> atriða til viðbótar</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Hreinsa tímabundnar forritaskrár?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Hreinsa tímabundnar forritaskrár"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vill fá að hreinsa sumar tímabundnar skrár. Þetta getur haft í för með sér aukna rafhlöðunotkun eða notkun farsímagagna."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Verið er að eyða tímabundnum forritaskrám…"</string>
+ <string name="clear" msgid="5524638938415865915">"Hreinsa"</string>
<string name="allow" msgid="8885707816848569619">"Leyfa"</string>
<string name="deny" msgid="6040983710442068936">"Hafna"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index e8d291a..9b5d598 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">Più altri <xliff:g id="COUNT_1">^1</xliff:g> elementi</item>
<item quantity="one">Più <xliff:g id="COUNT_0">^1</xliff:g> altro elemento</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Cancellare i file temporanei delle app?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Cancellare file temporanei delle app"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"L\'app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vorrebbe cancellare alcuni file temporanei. In tal caso potrebbe verificarsi un maggiore utilizzo della batteria o della rete dati."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Cancellazione dei file temporanei delle app…"</string>
+ <string name="clear" msgid="5524638938415865915">"Cancella"</string>
<string name="allow" msgid="8885707816848569619">"Consenti"</string>
<string name="deny" msgid="6040983710442068936">"Rifiuta"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 2238a61..d078c28 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -19,7 +19,7 @@
<string name="uid_label" msgid="8421971615411294156">"מדיה"</string>
<string name="storage_description" msgid="4081716890357580107">"אחסון מקומי"</string>
<string name="app_label" msgid="9035307001052716210">"אחסון מדיה"</string>
- <string name="artist_label" msgid="8105600993099120273">"אמן"</string>
+ <string name="artist_label" msgid="8105600993099120273">"אומן"</string>
<string name="unknown" msgid="2059049215682829375">"לא ידוע"</string>
<string name="root_images" msgid="5861633549189045666">"תמונות"</string>
<string name="root_videos" msgid="8792703517064649453">"סרטונים"</string>
@@ -41,9 +41,10 @@
<item quantity="other">ועוד <xliff:g id="COUNT_1">^1</xliff:g> פריטים נוספים</item>
<item quantity="one">ועוד פריט אחד נוסף (<xliff:g id="COUNT_0">^1</xliff:g>)</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"לנקות קובצי אפליקציה זמניים?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"ניקוי קובצי אפליקציה זמניים"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"קיבלת בקשה מהאפליקציה <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> לניקוי של חלק מהקבצים הזמניים. הפעולה עשויה להגביר את השימוש בסוללה או בחבילת הגלישה."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"מתבצע ניקוי של קובצי אפליקציה זמניים…"</string>
+ <string name="clear" msgid="5524638938415865915">"ניקוי"</string>
<string name="allow" msgid="8885707816848569619">"אישור"</string>
<string name="deny" msgid="6040983710442068936">"דחייה"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index b7b0c5b..a7795b9 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">他 <xliff:g id="COUNT_1">^1</xliff:g> 件の項目</item>
<item quantity="one">他 <xliff:g id="COUNT_0">^1</xliff:g> 件の項目</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"アプリの一時ファイルを削除しますか?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"アプリの一時ファイルの削除"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>が一部の一時ファイルを削除する権限を求めています。この処理により、電池やモバイルデータの使用量が増えることがあります。"</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"アプリの一時ファイルを削除しています…"</string>
+ <string name="clear" msgid="5524638938415865915">"削除"</string>
<string name="allow" msgid="8885707816848569619">"許可"</string>
<string name="deny" msgid="6040983710442068936">"許可しない"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index b1d0b87..420e846 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">და კიდევ <xliff:g id="COUNT_1">^1</xliff:g> დამატებითი ერთეული</item>
<item quantity="one">და კიდევ <xliff:g id="COUNT_0">^1</xliff:g> დამატებითი ერთეული</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"გასუფთავდეს აპის დროებითი ფაილები?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"გასუფთავდეს აპის დროებითი ფაილები?"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>-ს სურს, გაასუფთაოს დროებითი ფაილები. ამან შეიძლება ზოგიერთი ბატარეის ან მობილური ინტერნეტის გაზრდილი მოხმარება გამოიწვიოს."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"მიმდინარეობს აპის დროებითი ფაილების გასუფთავება…"</string>
+ <string name="clear" msgid="5524638938415865915">"გასუფთავება"</string>
<string name="allow" msgid="8885707816848569619">"დაშვება"</string>
<string name="deny" msgid="6040983710442068936">"უარყოფა"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 161809b..1b899b2 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">Тағы <xliff:g id="COUNT_1">^1</xliff:g> элемент</item>
<item quantity="one">Тағы <xliff:g id="COUNT_0">^1</xliff:g> элемент</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Қолданбаның уақытша файлдарын өшіру керек пе?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Қолданбаның уақытша файлдарын өшіру"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> кейбір уақытша файлдарды өшіргісі келеді. Соған байланысты батарея тез отыруы немесе мобильдік интернет трафигі көп кетуі мүмкін."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Қолданбаның уақытша файлдары өшірілуде…"</string>
+ <string name="clear" msgid="5524638938415865915">"Өшіру"</string>
<string name="allow" msgid="8885707816848569619">"Рұқсат ету"</string>
<string name="deny" msgid="6040983710442068936">"Тыйым салу"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index a87025e..b4a930f 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">បូករួមទាំងធាតុ <xliff:g id="COUNT_1">^1</xliff:g> បន្ថែមទៀត</item>
<item quantity="one">បូករួមទាំងធាតុ <xliff:g id="COUNT_0">^1</xliff:g> បន្ថែមទៀត</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"សម្អាតឯកសារកម្មវិធីបណ្ដោះអាសន្នឬ?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"សម្អាតឯកសារកម្មវិធីបណ្ដោះអាសន្ន"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ចង់សម្អាតឯកសារបណ្ដោះអាសន្នមួយចំនួន។ សកម្មភាពនេះអាចបណ្ដាលឱ្យការប្រើប្រាស់ថ្ម ឬទិន្នន័យទូរសព្ទចល័តមានការកើនឡើង។"</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"កំពុងសម្អាតឯកសារកម្មវិធីបណ្ដោះអាសន្ន…"</string>
+ <string name="clear" msgid="5524638938415865915">"សម្អាត"</string>
<string name="allow" msgid="8885707816848569619">"អនុញ្ញាត"</string>
<string name="deny" msgid="6040983710442068936">"បដិសេធ"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 1896b5f..99c1788 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -21,7 +21,7 @@
<string name="app_label" msgid="9035307001052716210">"ಮಾಧ್ಯಮ ಸಂಗ್ರಹಣೆ"</string>
<string name="artist_label" msgid="8105600993099120273">"ಕಲಾವಿದರು"</string>
<string name="unknown" msgid="2059049215682829375">"ಅಪರಿಚಿತ"</string>
- <string name="root_images" msgid="5861633549189045666">"ಚಿತ್ರಗಳು"</string>
+ <string name="root_images" msgid="5861633549189045666">"Images"</string>
<string name="root_videos" msgid="8792703517064649453">"ವೀಡಿಯೊಗಳು"</string>
<string name="root_audio" msgid="3505830755201326018">"ಆಡಿಯೊ"</string>
<string name="root_documents" msgid="3829103301363849237">"ಡಾಕ್ಯುಮೆಂಟ್ಗಳು"</string>
@@ -37,9 +37,10 @@
<item quantity="one">ಜೊತೆಗೆ <xliff:g id="COUNT_1">^1</xliff:g> ಹೆಚ್ಚುವರಿ ಐಟಂಗಳು</item>
<item quantity="other">ಜೊತೆಗೆ <xliff:g id="COUNT_1">^1</xliff:g> ಹೆಚ್ಚುವರಿ ಐಟಂಗಳು</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"ತಾತ್ಕಾಲಿಕ ಆ್ಯಪ್ ಫೈಲ್ಗಳನ್ನು ತೆರವುಗೊಳಿಸಬೇಕೇ?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"ತಾತ್ಕಾಲಿಕ ಆ್ಯಪ್ ಫೈಲ್ಗಳನ್ನು ತೆರವುಗೊಳಿಸಿ"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>, ಕೆಲವು ತಾತ್ಕಾಲಿಕ ಫೈಲ್ಗಳನ್ನು ತೆರವುಗೊಳಿಸಲು ಬಯಸುತ್ತಿದೆ. ಬ್ಯಾಟರಿ ಅಥವಾ ಸೆಲ್ಯುಲರ್ ಡೇಟಾ ಹೆಚ್ಚು ಬಳಕೆಯಾಗಲು ಇದು ಕಾರಣವಾಗಬಹುದು."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"ತಾತ್ಕಾಲಿಕ ಆ್ಯಪ್ ಫೈಲ್ಗಳನ್ನು ತೆರವುಗೊಳಿಸಲಾಗುತ್ತಿದೆ…"</string>
+ <string name="clear" msgid="5524638938415865915">"ತೆರವುಗೊಳಿಸಿ"</string>
<string name="allow" msgid="8885707816848569619">"ಅನುಮತಿಸಿ"</string>
<string name="deny" msgid="6040983710442068936">"ನಿರಾಕರಿಸಿ"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 43c798f..97fa4ec 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">그 외 항목 <xliff:g id="COUNT_1">^1</xliff:g>개</item>
<item quantity="one">그 외 항목 <xliff:g id="COUNT_0">^1</xliff:g>개</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"임시 앱 파일을 삭제하시겠습니까?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"임시 앱 파일 삭제"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>에서 일부 임시 파일을 삭제하려고 합니다. 이로 인해 배터리 또는 모바일 데이터 사용량이 늘어날 수 있습니다."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"임시 앱 파일 삭제 중…"</string>
+ <string name="clear" msgid="5524638938415865915">"삭제"</string>
<string name="allow" msgid="8885707816848569619">"허용"</string>
<string name="deny" msgid="6040983710442068936">"거부"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 38642b0..6198dba 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">Дагы <xliff:g id="COUNT_1">^1</xliff:g> нерсе</item>
<item quantity="one">Дагы <xliff:g id="COUNT_0">^1</xliff:g> нерсе</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Колдонмодогу убактылуу файлдарды өчүрөсүзбү?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Колдонмодогу убактылуу файлдарды өчүрүү"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> айрым убактылуу файлдарды өчүргөнү жатат. Батарея же мобилдик Интернет өтө көп колдонулушу мүмкүн."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Колдонмодогу убактылуу файлдар өчүрүлүүдө…"</string>
+ <string name="clear" msgid="5524638938415865915">"Тазалоо"</string>
<string name="allow" msgid="8885707816848569619">"Уруксат берүү"</string>
<string name="deny" msgid="6040983710442068936">"Тыюу салуу"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index f14e1c3..568d20a 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">ຮວມ <xliff:g id="COUNT_1">^1</xliff:g> ລາຍການເພີ່ມເຕີມ</item>
<item quantity="one">ຮວມ <xliff:g id="COUNT_0">^1</xliff:g> ລາຍການເພີ່ມເຕີມ</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"ລຶບລ້າງໄຟລ໌ແອັບຊົ່ວຄາວບໍ?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"ລຶບລ້າງໄຟລ໌ແອັບຊົ່ວຄາວ"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ຕ້ອງການລ້າງໄຟລ໌ຊົ່ວຄາວບາງຢ່າງອອກ. ນີ້ອາດເຮັດໃຫ້ມີການໃຊ້ແບັດເຕີຣີ ຫຼື ອິນເຕີເນັດມືຖືຫຼາຍຂຶ້ນ."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"ກຳລັງລຶບລ້າງໄຟລ໌ແອັບຊົ່ວຄາວ…"</string>
+ <string name="clear" msgid="5524638938415865915">"ລຶບລ້າງ"</string>
<string name="allow" msgid="8885707816848569619">"ອະນຸຍາດ"</string>
<string name="deny" msgid="6040983710442068936">"ປະຕິເສດ"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 5cf0dad..4190c0f 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -41,9 +41,10 @@
<item quantity="many">Dar <xliff:g id="COUNT_1">^1</xliff:g> papildomo elemento</item>
<item quantity="other">Dar <xliff:g id="COUNT_1">^1</xliff:g> papildomų elementų</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Išvalyti laikinus programų failus?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Laikinų programų failų išvalymas"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"Programa „<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>“ nori išvalyti kai kuriuos laikinus failus. Dėl to gali būti suvartojama daugiau akumuliatoriaus energijos ar mobiliojo ryšio duomenų."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Išvalomi laikini programos failai…"</string>
+ <string name="clear" msgid="5524638938415865915">"Išvalyti"</string>
<string name="allow" msgid="8885707816848569619">"Leisti"</string>
<string name="deny" msgid="6040983710442068936">"Atmesti"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index af20087..7bc296f 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -39,9 +39,10 @@
<item quantity="one">Un vēl <xliff:g id="COUNT_1">^1</xliff:g> vienums</item>
<item quantity="other">Un vēl <xliff:g id="COUNT_1">^1</xliff:g> vienumi</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Vai notīrīt lietotņu pagaidu failus?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Lietotņu pagaidu failu notīrīšana"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"Lietotne <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vēlas iegūt atļauju notīrīt dažus pagaidu failus. Tas var palielināt akumulatora izmantošanas ilgumu vai mobilo datu lietojumu."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Notiek lietotņu pagaidu failu notīrīšana…"</string>
+ <string name="clear" msgid="5524638938415865915">"Notīrīt"</string>
<string name="allow" msgid="8885707816848569619">"Atļaut"</string>
<string name="deny" msgid="6040983710442068936">"Neatļaut"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 8683cbd..9dd0bf3 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -37,9 +37,10 @@
<item quantity="one">Плус <xliff:g id="COUNT_1">^1</xliff:g> дополнителна ставка</item>
<item quantity="other">Плус <xliff:g id="COUNT_1">^1</xliff:g> дополнителни ставки</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Да се избришат привремените датотеки на апликацијата?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Избриши ги привремените датотеки на апликацијата"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> сака да избрише некои привремени датотеки. Поради тоа може да дојде до зголемено користење на батеријата или мобилниот интернет."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Се бришат привремените датотеки на апликацијата…"</string>
+ <string name="clear" msgid="5524638938415865915">"Избриши"</string>
<string name="allow" msgid="8885707816848569619">"Дозволи"</string>
<string name="deny" msgid="6040983710442068936">"Одбиј"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 9150998..d505748 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -21,7 +21,7 @@
<string name="app_label" msgid="9035307001052716210">"മീഡിയ സ്റ്റോറേജ്"</string>
<string name="artist_label" msgid="8105600993099120273">"ആർട്ടിസ്റ്റ്"</string>
<string name="unknown" msgid="2059049215682829375">"അജ്ഞാതം"</string>
- <string name="root_images" msgid="5861633549189045666">"ചിത്രങ്ങൾ"</string>
+ <string name="root_images" msgid="5861633549189045666">"Images"</string>
<string name="root_videos" msgid="8792703517064649453">"വീഡിയോകൾ"</string>
<string name="root_audio" msgid="3505830755201326018">"ഓഡിയോ"</string>
<string name="root_documents" msgid="3829103301363849237">"ഡോക്യുമെന്റുകൾ"</string>
@@ -37,9 +37,10 @@
<item quantity="other"><xliff:g id="COUNT_1">^1</xliff:g> അധിക ഇനങ്ങൾ കൂടി</item>
<item quantity="one"><xliff:g id="COUNT_0">^1</xliff:g> അധിക ഇനം കൂടി</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"താൽക്കാലികമായ ആപ്പ് ഫയലുകൾ മായ്ക്കണോ?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"താൽക്കാലികമായ ആപ്പ് ഫയലുകൾ മായ്ക്കുക"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> എന്നതിന് കുറച്ച് താൽക്കാലിക ഫയലുകൾ മായ്ക്കണമെന്നുണ്ട്. ബാറ്ററിയുടെയോ സെല്ലുലാർ ഡാറ്റയുടെയോ വർദ്ധിച്ച ഉപയോഗത്തിന് ഇത് കാരണമായേക്കാം."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"താൽക്കാലികമായ ആപ്പ് ഫയലുകൾ മായ്ക്കുന്നു…"</string>
+ <string name="clear" msgid="5524638938415865915">"മായ്ക്കുക"</string>
<string name="allow" msgid="8885707816848569619">"അനുവദിക്കൂ"</string>
<string name="deny" msgid="6040983710442068936">"നിരസിക്കുക"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index c1153cf..8c7a39b 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">Нэмээд нэмэлт <xliff:g id="COUNT_1">^1</xliff:g> зүйл</item>
<item quantity="one">Нэмээд нэмэлт <xliff:g id="COUNT_0">^1</xliff:g> зүйл</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Аппын түр зуурын файлуудыг арилгах уу?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Аппын түр зуурын файлуудыг арилгах"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> нь түр зуурын зарим файлыг арилгах хүсэлтэй байна. Энэ нь батарей эсвэл мобайл дата ашиглалтыг нэмэгдүүлэхэд хүргэж болзошгүй."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Аппын түр зуурын файлуудыг арилгаж байна…"</string>
+ <string name="clear" msgid="5524638938415865915">"Арилгах"</string>
<string name="allow" msgid="8885707816848569619">"Зөвшөөрөх"</string>
<string name="deny" msgid="6040983710442068936">"Татгалзах"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index da22d60..b110be3 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -21,7 +21,7 @@
<string name="app_label" msgid="9035307001052716210">"मीडिया स्टोरेज"</string>
<string name="artist_label" msgid="8105600993099120273">"कलाकार"</string>
<string name="unknown" msgid="2059049215682829375">"अज्ञात"</string>
- <string name="root_images" msgid="5861633549189045666">"इमेज"</string>
+ <string name="root_images" msgid="5861633549189045666">"Images"</string>
<string name="root_videos" msgid="8792703517064649453">"व्हिडिओ"</string>
<string name="root_audio" msgid="3505830755201326018">"ऑडिओ"</string>
<string name="root_documents" msgid="3829103301363849237">"दस्तऐवज"</string>
@@ -37,9 +37,10 @@
<item quantity="other">आणखी <xliff:g id="COUNT_1">^1</xliff:g> अतिरिक्त आयटम</item>
<item quantity="one">आणखी <xliff:g id="COUNT_0">^1</xliff:g> अतिरिक्त आयटम</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"तात्पुरत्या अॅप फाइल काढून टाकायच्या आहेत का?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"तात्पुरत्या अॅप फाइल साफ करा"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ला काही तात्पुरत्या फाइल साफ करायच्या आहेत. यामुळे बॅटरी किंवा सेल्युलर डेटाच्या वापरात वाढ होऊ शकते."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"तात्पुरत्या ॲप फाइल काढून टाकत आहे…"</string>
+ <string name="clear" msgid="5524638938415865915">"साफ करा"</string>
<string name="allow" msgid="8885707816848569619">"अनुमती द्या"</string>
<string name="deny" msgid="6040983710442068936">"नकार द्या"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 8e703b6..067cc43 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">Serta <xliff:g id="COUNT_1">^1</xliff:g> item tambahan</item>
<item quantity="one">Serta <xliff:g id="COUNT_0">^1</xliff:g> item tambahan</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Kosongkan fail apl sementara?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Kosongkan fail apl sementara"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> mahu mengosongkan beberapa fail sementara. Tindakan ini mungkin menyebabkan peningkatan penggunaan bateri atau data selular."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Mengosongkan fail apl sementara…"</string>
+ <string name="clear" msgid="5524638938415865915">"Kosongkan"</string>
<string name="allow" msgid="8885707816848569619">"Benarkan"</string>
<string name="deny" msgid="6040983710442068936">"Tolak"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index ee0c757..ab3766c 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">ထပ်ပေါင်းအရာ <xliff:g id="COUNT_1">^1</xliff:g> ခု အပါအဝင်</item>
<item quantity="one">ထပ်ပေါင်းအရာ <xliff:g id="COUNT_0">^1</xliff:g> ခု အပါအဝင်</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"ယာယီအက်ပ်ဖိုင်များ ရှင်းထုတ်မလား။"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"ယာယီအက်ပ်ဖိုင်များ ရှင်းရန်"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> သည် ယာယီဖိုင်များမှ အချို့ကို ရှင်းထုတ်လိုသည်။ ထို့ကြောင့် ဘက်ထရီ သို့မဟုတ် ဆယ်လူလာဒေတာ အသုံးပြုမှု မြင့်တက်လာနိုင်သည်။"</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"ယာယီအက်ပ်ဖိုင်များ ရှင်းထုတ်နေသည်…"</string>
+ <string name="clear" msgid="5524638938415865915">"ရှင်းရန်"</string>
<string name="allow" msgid="8885707816848569619">"ခွင့်ပြုရန်"</string>
<string name="deny" msgid="6040983710442068936">"ပယ်ရန်"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 25a2710..35fd892 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">Pluss <xliff:g id="COUNT_1">^1</xliff:g> elementer til</item>
<item quantity="one">Pluss <xliff:g id="COUNT_0">^1</xliff:g> element til</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Vil du slette midlertidige appfiler?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Slett midlertidige appfiler"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vil slette noen midlertidige filer. Dette kan resultere i økt bruk av batteri eller mobildata."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Sletter midlertidige appfiler …"</string>
+ <string name="clear" msgid="5524638938415865915">"Slett"</string>
<string name="allow" msgid="8885707816848569619">"Tillat"</string>
<string name="deny" msgid="6040983710442068936">"Avvis"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 835a9be..0735ae7 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">थप <xliff:g id="COUNT_1">^1</xliff:g> वटा अतिरिक्त वस्तु</item>
<item quantity="one">थप <xliff:g id="COUNT_0">^1</xliff:g> अतिरिक्त वस्तु</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"अनुप्रयोगका अस्थायी फाइलहरू मेटाउने हो?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"एपका अस्थायी फाइलहरू हटाउनुहोस्"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> केही अस्थायी फाइलहरू मेटाउन चाहन्छ। यो कार्य गर्ने अनुमति दिनुभएका खण्डमा ब्याट्रीको खपत वा सेलुलर डेटाको प्रयोग बढ्न सक्छ।"</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"एपका अस्थायी फाइलहरू मेटाउँदै…"</string>
+ <string name="clear" msgid="5524638938415865915">"हटाउनुहोस्"</string>
<string name="allow" msgid="8885707816848569619">"अनुमति दिनुहोस्"</string>
<string name="deny" msgid="6040983710442068936">"अस्वीकार गर्नुहोस्"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
@@ -51,8 +52,8 @@
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> लाई यो भिडियो परिमार्जन गर्न दिने हो?</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>
+ <item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> लाई यी <xliff:g id="COUNT">^2</xliff:g> फोटोहरू परिमार्जन गर्न दिने हो?</item>
+ <item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> लाई यो फोटो परिमार्जन गर्न दिने हो?</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>
@@ -67,8 +68,8 @@
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> लाई यो भिडियो सारेर रद्दीको टोकरीमा लैजान दिने हो?</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>
+ <item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> लाई यी <xliff:g id="COUNT">^2</xliff:g> फोटोहरू सारेर रद्दीको टोकरीमा लैजान दिने हो?</item>
+ <item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> लाई यो फोटो सारेर रद्दीको टोकरीमा लैजान दिने हो?</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>
@@ -83,8 +84,8 @@
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> लाई यो भिडियो रद्दीको टोकरीबाट निकालेर ल्याउन दिने हो?</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>
+ <item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> लाई यी <xliff:g id="COUNT">^2</xliff:g> फोटोहरू रद्दीको टोकरीबाट निकालेर ल्याउन दिने हो?</item>
+ <item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> लाई यो फोटो रद्दीको टोकरीबाट निकालेर ल्याउन दिने हो?</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>
@@ -99,8 +100,8 @@
<item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> लाई यो भिडियो मेटाउन दिने हो?</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>
+ <item quantity="other"><xliff:g id="APP_NAME_1">^1</xliff:g> लाई यी <xliff:g id="COUNT">^2</xliff:g> फोटोहरू मेटाउन दिने हो?</item>
+ <item quantity="one"><xliff:g id="APP_NAME_0">^1</xliff:g> लाई यो फोटो मेटाउन दिने हो?</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>
diff --git a/res/values-night/colors.xml b/res/values-night/colors.xml
index 56d8417..1478eb2 100644
--- a/res/values-night/colors.xml
+++ b/res/values-night/colors.xml
@@ -16,5 +16,6 @@
-->
<resources>
- <color name="thumb_gray_color">#3c4043</color>
+ <color name="thumb_gray_color">#3C4043</color>
+ <color name="clear_cache_icon_color">#DADCE0</color>
</resources>
diff --git a/res/values-night/styles.xml b/res/values-night/styles.xml
new file mode 100644
index 0000000..9b4da23
--- /dev/null
+++ b/res/values-night/styles.xml
@@ -0,0 +1,38 @@
+<?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.
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <style name="PickerDialogTheme"
+ parent="@android:style/Theme.DeviceDefault.Dialog.Alert">
+ <item name="android:windowNoTitle">true</item>
+ </style>
+
+ <style name="AlertDialogTheme"
+ parent="@android:style/Theme.DeviceDefault.Dialog.Alert"/>
+
+ <style name="CacheClearingAlertDialogTheme"
+ parent="@android:style/Theme.DeviceDefault.Dialog.Alert">
+ <item name="android:windowIsTranslucent">true</item>
+ <item name="android:windowBackground">@android:color/transparent</item>
+ <item name="android:windowContentOverlay">@null</item>
+ <item name="android:windowNoTitle">true</item>
+ <item name="android:windowIsFloating">true</item>
+ <item name="android:backgroundDimEnabled">true</item>
+ <item name="android:alertDialogTheme">@style/AlertDialogTheme</item>
+ </style>
+
+</resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 18803cc..d685675 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -25,7 +25,7 @@
<string name="root_videos" msgid="8792703517064649453">"Video\'s"</string>
<string name="root_audio" msgid="3505830755201326018">"Audio"</string>
<string name="root_documents" msgid="3829103301363849237">"Documenten"</string>
- <string name="permission_required" msgid="1460820436132943754">"Toestemming vereist om dit item aan te passen of te verwijderen."</string>
+ <string name="permission_required" msgid="1460820436132943754">"Rechten vereist om dit item aan te passen of te verwijderen."</string>
<string name="permission_required_action" msgid="706370952366113539">"Doorgaan"</string>
<string name="grant_dialog_button_allow" msgid="1644287024501033471">"Toestaan"</string>
<string name="grant_dialog_button_deny" msgid="6190589471415815741">"Weigeren"</string>
@@ -37,9 +37,10 @@
<item quantity="other">Plus <xliff:g id="COUNT_1">^1</xliff:g> extra items</item>
<item quantity="one">Plus <xliff:g id="COUNT_0">^1</xliff:g> extra item</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Tijdelijke app-bestanden wissen?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Tijdelijke app-bestanden wissen"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> wil een aantal tijdelijke bestanden wissen. Dit kan leiden tot een groter verbruik van de batterij of mobiele data."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Tijdelijke app-bestanden wissen…"</string>
+ <string name="clear" msgid="5524638938415865915">"Wissen"</string>
<string name="allow" msgid="8885707816848569619">"Toestaan"</string>
<string name="deny" msgid="6040983710442068936">"Weigeren"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 1554b52..5ea6ea3 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -21,7 +21,7 @@
<string name="app_label" msgid="9035307001052716210">"ମିଡିଆ ଷ୍ଟୋରେଜ୍"</string>
<string name="artist_label" msgid="8105600993099120273">"କଳାକାର"</string>
<string name="unknown" msgid="2059049215682829375">"ଅଜଣା"</string>
- <string name="root_images" msgid="5861633549189045666">"ଇମେଜ୍"</string>
+ <string name="root_images" msgid="5861633549189045666">"Images"</string>
<string name="root_videos" msgid="8792703517064649453">"ଭିଡିଓ"</string>
<string name="root_audio" msgid="3505830755201326018">"ଅଡିଓ"</string>
<string name="root_documents" msgid="3829103301363849237">"ଡକ୍ୟୁମେଣ୍ଟଗୁଡ଼ିକ"</string>
@@ -37,9 +37,10 @@
<item quantity="other">ଅଧିକ <xliff:g id="COUNT_1">^1</xliff:g>ଟି ଅତିରିକ୍ତ ଆଇଟମ୍</item>
<item quantity="one">ଅଧିକ <xliff:g id="COUNT_0">^1</xliff:g>ଟି ଅତିରିକ୍ତ ଆଇଟମ୍</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"ଅସ୍ଥାୟୀ ଆପ୍ ଫାଇଲଗୁଡ଼ିକୁ ଖାଲି କରିବେ?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"ଅସ୍ଥାୟୀ ଆପ୍ ଫାଇଲଗୁଡ଼ିକୁ ଖାଲି କରନ୍ତୁ"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> କିଛି ଅସ୍ଥାୟୀ ଫାଇଲ୍ ଖାଲି କରିବାକୁ ଚାହୁଁଛି। ଏହା ଫଳରେ ବ୍ୟାଟେରୀ କିମ୍ବା ସେଲ୍ୟୁଲାର୍ ଡାଟାର ବ୍ୟବହାର ଅଧିକ ହୋଇପାରେ।"</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"ଅସ୍ଥାୟୀ ଆପ୍ ଫାଇଲଗୁଡ଼ିକୁ ଖାଲି କରାଯାଉଛି…"</string>
+ <string name="clear" msgid="5524638938415865915">"ଖାଲି କରନ୍ତୁ"</string>
<string name="allow" msgid="8885707816848569619">"ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="deny" msgid="6040983710442068936">"ଅଗ୍ରାହ୍ୟ କରନ୍ତୁ"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index c598bda..cb5e9b4 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -37,9 +37,10 @@
<item quantity="one">ਇਸ ਤੋਂ ਇਲਾਵਾ <xliff:g id="COUNT_1">^1</xliff:g> ਵਾਧੂ ਆਈਟਮ</item>
<item quantity="other">ਇਸ ਤੋਂ ਇਲਾਵਾ <xliff:g id="COUNT_1">^1</xliff:g> ਵਾਧੂ ਆਈਟਮਾਂ</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"ਕੀ ਅਸਥਾਈ ਐਪ ਫ਼ਾਈਲਾਂ ਨੂੰ ਕਲੀਅਰ ਕਰਨਾ ਹੈ?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"ਅਸਥਾਈ ਐਪ ਫ਼ਾਈਲਾਂ ਨੂੰ ਕਲੀਅਰ ਕਰੋ"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ਕੁਝ ਅਸਥਾਈ ਫ਼ਾਈਲਾਂ ਕਲੀਅਰ ਕਰਨਾ ਚਾਹੁੰਦੀ ਹੈ। ਇਸਦੇ ਨਤੀਜੇ ਵਜੋਂ ਬੈਟਰੀ ਜਾਂ ਸੈਲਿਊਲਰ ਡਾਟਾ ਦੀ ਵਰਤੋਂ ਵਧ ਸਕਦੀ ਹੈ।"</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"ਅਸਥਾਈ ਐਪ ਫ਼ਾਈਲਾਂ ਨੂੰ ਕਲੀਅਰ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ…"</string>
+ <string name="clear" msgid="5524638938415865915">"ਕਲੀਅਰ ਕਰੋ"</string>
<string name="allow" msgid="8885707816848569619">"ਆਗਿਆ ਦਿਓ"</string>
<string name="deny" msgid="6040983710442068936">"ਮਨ੍ਹਾ ਕਰੋ"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index b4a3897..ea4a8ce 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -41,9 +41,10 @@
<item quantity="other">I <xliff:g id="COUNT_1">^1</xliff:g> dodatkowego elementu</item>
<item quantity="one">I <xliff:g id="COUNT_0">^1</xliff:g> dodatkowy element</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Usunąć tymczasowe pliki aplikacji?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Usuwanie tymczasowych plików aplikacji"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"Aplikacja <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> chce usunąć niektóre pliki tymczasowe. Może to spowodować zwiększenie wykorzystania baterii lub komórkowej transmisji danych."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Usuwam tymczasowe pliki aplikacji…"</string>
+ <string name="clear" msgid="5524638938415865915">"Wyczyść"</string>
<string name="allow" msgid="8885707816848569619">"Zezwól"</string>
<string name="deny" msgid="6040983710442068936">"Odmów"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-pt-rBR/strings.xml b/res/values-pt-rBR/strings.xml
index 042ceef..d0ff6d6 100644
--- a/res/values-pt-rBR/strings.xml
+++ b/res/values-pt-rBR/strings.xml
@@ -37,9 +37,10 @@
<item quantity="one">Mais <xliff:g id="COUNT_1">^1</xliff:g> item extra</item>
<item quantity="other">Mais <xliff:g id="COUNT_1">^1</xliff:g> itens extras</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Limpar arquivos temporários de apps?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Limpar arquivos temporários de apps"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"O app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> quer apagar alguns arquivos temporários. Isso pode aumentar o uso de bateria ou de dados da rede celular."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Limpando arquivos temporários de apps…"</string>
+ <string name="clear" msgid="5524638938415865915">"Limpar"</string>
<string name="allow" msgid="8885707816848569619">"Permitir"</string>
<string name="deny" msgid="6040983710442068936">"Negar"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 6d0cb80..27c1cb0 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">E <xliff:g id="COUNT_1">^1</xliff:g> itens adicionais</item>
<item quantity="one">E <xliff:g id="COUNT_0">^1</xliff:g> item adicional</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Pretende limpar os ficheiros temporários da app?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Limpe ficheiros de apps temporários"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"A app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> pretende limpar alguns ficheiros temporários. Isto pode resultar num aumento da utilização da bateria ou dos dados móveis."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"A limpar ficheiros temporários da app…"</string>
+ <string name="clear" msgid="5524638938415865915">"Limpar"</string>
<string name="allow" msgid="8885707816848569619">"Permitir"</string>
<string name="deny" msgid="6040983710442068936">"Recusar"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 042ceef..d0ff6d6 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -37,9 +37,10 @@
<item quantity="one">Mais <xliff:g id="COUNT_1">^1</xliff:g> item extra</item>
<item quantity="other">Mais <xliff:g id="COUNT_1">^1</xliff:g> itens extras</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Limpar arquivos temporários de apps?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Limpar arquivos temporários de apps"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"O app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> quer apagar alguns arquivos temporários. Isso pode aumentar o uso de bateria ou de dados da rede celular."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Limpando arquivos temporários de apps…"</string>
+ <string name="clear" msgid="5524638938415865915">"Limpar"</string>
<string name="allow" msgid="8885707816848569619">"Permitir"</string>
<string name="deny" msgid="6040983710442068936">"Negar"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 77e8db2..8df20b8 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -39,9 +39,10 @@
<item quantity="other">Și încă <xliff:g id="COUNT_1">^1</xliff:g> de elemente</item>
<item quantity="one">Și încă <xliff:g id="COUNT_0">^1</xliff:g> element</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Ștergeți fișierele temporare ale aplicațiilor?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Ștergeți fișierele temporare ale aplicațiilor"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vrea să șteargă fișiere temporare. Aceasta poate duce la creșterea gradului de utilizare a bateriei sau a datelor mobile."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Se șterg fișierele temporare ale aplicațiilor…"</string>
+ <string name="clear" msgid="5524638938415865915">"Ștergeți"</string>
<string name="allow" msgid="8885707816848569619">"Permiteți"</string>
<string name="deny" msgid="6040983710442068936">"Refuzați"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index c423cdb..d7a1aaa 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -41,9 +41,10 @@
<item quantity="many">и ещё <xliff:g id="COUNT_1">^1</xliff:g> объектов</item>
<item quantity="other">и ещё <xliff:g id="COUNT_1">^1</xliff:g> объекта</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Удалить временные файлы приложения?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Удалить временные файлы приложений"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"Приложение \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\" запрашивает разрешение на удаление временных файлов. Это может увеличить расход заряда или трафика."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Удаление временных файлов приложения…"</string>
+ <string name="clear" msgid="5524638938415865915">"Удалить"</string>
<string name="allow" msgid="8885707816848569619">"Разрешить"</string>
<string name="deny" msgid="6040983710442068936">"Запретить"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index cc7435c..ad22297 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -37,9 +37,10 @@
<item quantity="one">සහ අමතර අයිතම <xliff:g id="COUNT_1">^1</xliff:g></item>
<item quantity="other">සහ අමතර අයිතම <xliff:g id="COUNT_1">^1</xliff:g></item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"තාවකාලික යෙදුම් ගොනු හිස් කරන්නද?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"තාවකාලික යෙදුම් ගොනු හිස් කරන්න"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> සමහර තාවකාලික ගොනු හිස් කිරීමට කැමතියි. මෙය බැටරි බලයේ හෝ සෙලියුලර් දත්තවල වැඩි භාවිතයකට හේතු විය හැකිය."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"තාවකාලික යෙදුම් ගොනු හිස් කරමින්…"</string>
+ <string name="clear" msgid="5524638938415865915">"හිස් කරන්න"</string>
<string name="allow" msgid="8885707816848569619">"ඉඩ දෙන්න"</string>
<string name="deny" msgid="6040983710442068936">"ප්රතික්ෂේප කරන්න"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index b9d6a81..359ba24 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -41,9 +41,10 @@
<item quantity="other">A <xliff:g id="COUNT_1">^1</xliff:g> ďalších položiek</item>
<item quantity="one">A <xliff:g id="COUNT_0">^1</xliff:g> ďalšia položka</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Chcete vymazať dočasné súbory aplikácie?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Vymazanie dočasných súborov aplikácií"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"Aplikácia <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> chce vymazať niekoľko dočasných súborov. To môže viesť k vyššiemu využívaniu batérie alebo mobilných dát."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Odstraňujú sa dočasné súbory aplikácie…"</string>
+ <string name="clear" msgid="5524638938415865915">"Vymazať"</string>
<string name="allow" msgid="8885707816848569619">"Povoliť"</string>
<string name="deny" msgid="6040983710442068936">"Zamietnuť"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 2d8bb2b..ff63498 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -41,9 +41,10 @@
<item quantity="few">In še <xliff:g id="COUNT_1">^1</xliff:g> dodatni elementi</item>
<item quantity="other">In še <xliff:g id="COUNT_1">^1</xliff:g> dodatnih elementov</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Želite izbrisati začasne datoteke aplikacij?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Brisanje začasnih datotek aplikacij"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"Aplikacija <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> želi izbrisati nekaj začasnih datotek. To lahko povzroči povečano porabo energije baterije ali povečan prenos podatkov v mobilnem omrežju."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Brisanje začasnih datotek aplikacij …"</string>
+ <string name="clear" msgid="5524638938415865915">"Počisti"</string>
<string name="allow" msgid="8885707816848569619">"Dovoli"</string>
<string name="deny" msgid="6040983710442068936">"Zavrni"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 25c1f56..1e90f35 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">Dhe <xliff:g id="COUNT_1">^1</xliff:g> artikuj të tjerë</item>
<item quantity="one">Dhe <xliff:g id="COUNT_0">^1</xliff:g> artikull tjetër</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Të pastrohen skedarët e përkohshëm të aplikacioneve?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Pastro skedarët e përkohshëm të aplikacioneve"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> dëshiron të pastrojë disa skedarë të përkohshëm. Kjo mund të rezultojë në një rritje të përdorimit të baterisë ose të të dhënave celulare."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Skedarët e përkohshëm të aplikacioneve po pastrohen…"</string>
+ <string name="clear" msgid="5524638938415865915">"Pastro"</string>
<string name="allow" msgid="8885707816848569619">"Lejo"</string>
<string name="deny" msgid="6040983710442068936">"Refuzo"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index c1e3bd8..079f9aa 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -39,9 +39,10 @@
<item quantity="few">И још <xliff:g id="COUNT_1">^1</xliff:g> ставке</item>
<item quantity="other">И још <xliff:g id="COUNT_1">^1</xliff:g> ставки</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Желите ли да обришете привремене датотеке апликација?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Обришите привремене датотеке апликација"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> жели да обрише неке привремене датотеке. Ово може да доведе до повећане потрошње батерије или мобилних података."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Бришу се привремене датотеке апликација…"</string>
+ <string name="clear" msgid="5524638938415865915">"Обриши"</string>
<string name="allow" msgid="8885707816848569619">"Дозволи"</string>
<string name="deny" msgid="6040983710442068936">"Одбиј"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index c19d34f..b0b990c 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">och <xliff:g id="COUNT_1">^1</xliff:g> objekt till</item>
<item quantity="one">och <xliff:g id="COUNT_0">^1</xliff:g> objekt till</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Vill du ta bort tillfälliga appfiler?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Rensa tillfälliga appfiler"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vill ta bort några tillfälliga filer. Det kan leda till ökad batteriförbrukning eller användning av mobildata."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Tillfälliga appfiler rensas …"</string>
+ <string name="clear" msgid="5524638938415865915">"Rensa"</string>
<string name="allow" msgid="8885707816848569619">"Tillåt"</string>
<string name="deny" msgid="6040983710442068936">"Neka"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index a3b2dc8..4917e30 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">Pamoja na vipengee <xliff:g id="COUNT_1">^1</xliff:g> zaidi</item>
<item quantity="one">Pamoja na kipengee <xliff:g id="COUNT_0">^1</xliff:g> zaidi</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Ungependa kufuta faili za muda za programu?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Futa faili za muda za programu"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ingependa kufuta baadhi ya faili za muda. Huenda hii ikasababisha kuongezeka kwa matumizi ya betri au data ya mtandao wa simu."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Inafuta faili za muda za programu…"</string>
+ <string name="clear" msgid="5524638938415865915">"Futa"</string>
<string name="allow" msgid="8885707816848569619">"Ruhusu"</string>
<string name="deny" msgid="6040983710442068936">"Kataa"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index c2b05ac..f13588a 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -21,7 +21,7 @@
<string name="app_label" msgid="9035307001052716210">"மீடியா சேமிப்பிடம்"</string>
<string name="artist_label" msgid="8105600993099120273">"கலைஞர்"</string>
<string name="unknown" msgid="2059049215682829375">"அறியாதது"</string>
- <string name="root_images" msgid="5861633549189045666">"படங்கள்"</string>
+ <string name="root_images" msgid="5861633549189045666">"Images"</string>
<string name="root_videos" msgid="8792703517064649453">"வீடியோக்கள்"</string>
<string name="root_audio" msgid="3505830755201326018">"ஆடியோ"</string>
<string name="root_documents" msgid="3829103301363849237">"ஆவணங்கள்"</string>
@@ -37,9 +37,10 @@
<item quantity="other">அத்துடன் கூடுதலாக <xliff:g id="COUNT_1">^1</xliff:g></item>
<item quantity="one">அத்துடன் கூடுதலாக <xliff:g id="COUNT_0">^1</xliff:g></item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"தற்காலிக ஆப்ஸ் ஃபைல்களை அழிக்கவா?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"ஆப்ஸின் தற்காலிக ஃபைல்களை அழித்தல்"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"சில தற்காலிக ஃபைல்களை நீக்குவதற்கு <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> அனுமதி கேட்கின்றது. இதனால் பேட்டரி அல்லது மொபைல் டேட்டா பயன்பாடு அதிகரிக்கக்கூடும்."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"ஆப்ஸிலுள்ள தற்காலிக ஃபைல்களை அழிக்கிறது…"</string>
+ <string name="clear" msgid="5524638938415865915">"அழி"</string>
<string name="allow" msgid="8885707816848569619">"அனுமதி"</string>
<string name="deny" msgid="6040983710442068936">"நிராகரி"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 24b12ea..30c0faa 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">దానితో పాటు, <xliff:g id="COUNT_1">^1</xliff:g> అదనపు అంశాలు</item>
<item quantity="one">దానితో పాటు, <xliff:g id="COUNT_0">^1</xliff:g> అదనపు అంశం</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"తాత్కాలిక యాప్ ఫైల్లను తొలగించాలా?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"తాత్కాలిక యాప్ ఫైల్లను క్లియర్ చేయండి"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"కొన్ని తాత్కాలిక ఫైల్స్ను క్లియర్ చేయడానికి <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> అనుమతి కోరుతోంది. దీని వలన బ్యాటరీ లేదా సెల్యూలార్ డేటా వినియోగం పెరగవచ్చు."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"తాత్కాలిక యాప్ ఫైల్లను క్లియర్ చేస్తోంది…"</string>
+ <string name="clear" msgid="5524638938415865915">"క్లియర్ చేయండి"</string>
<string name="allow" msgid="8885707816848569619">"అనుమతించు"</string>
<string name="deny" msgid="6040983710442068936">"నిరాకరించు"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index e3ed08a..db76bee 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">และอีก <xliff:g id="COUNT_1">^1</xliff:g> รายการ</item>
<item quantity="one">และอีก <xliff:g id="COUNT_0">^1</xliff:g> รายการ</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"ล้างไฟล์แอปชั่วคราวใช่ไหม"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"ล้างไฟล์แอปชั่วคราว"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ต้องการล้างไฟล์ชั่วคราวบางไฟล์ ซึ่งอาจส่งผลให้ใช้แบตเตอรี่หรืออินเทอร์เน็ตมือถือมากขึ้น"</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"กำลังล้างไฟล์แอปชั่วคราว…"</string>
+ <string name="clear" msgid="5524638938415865915">"ล้าง"</string>
<string name="allow" msgid="8885707816848569619">"อนุญาต"</string>
<string name="deny" msgid="6040983710442068936">"ปฏิเสธ"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 6502f43..79452b3 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -37,9 +37,10 @@
<item quantity="one">At <xliff:g id="COUNT_1">^1</xliff:g> pang item</item>
<item quantity="other">At <xliff:g id="COUNT_1">^1</xliff:g> pang item</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"I-clear ang mga pansamantalang file ng app?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"I-clear ang mga pansamantalang file ng app"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"Gustong mag-clear ng <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ng ilang pansamantalang file. Baka lumakas ang paggamit ng baterya o cellular data dahil dito."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Kini-clear ang mga pansamantalang file ng app…"</string>
+ <string name="clear" msgid="5524638938415865915">"I-clear"</string>
<string name="allow" msgid="8885707816848569619">"Payagan"</string>
<string name="deny" msgid="6040983710442068936">"Tanggihan"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 831946e..669eac9 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">Ayrıca <xliff:g id="COUNT_1">^1</xliff:g> ek öğe</item>
<item quantity="one">Ayrıca <xliff:g id="COUNT_0">^1</xliff:g> ek öğe</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Geçici uygulama dosyaları temizlensin mi?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Geçici uygulama dosyalarını temizleyin"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> bazı geçici dosyaları temizlemek istiyor. Bu, pil veya hücresel veri kullanımında artışa yol açabilir."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Geçici uygulama dosyaları temizleniyor…"</string>
+ <string name="clear" msgid="5524638938415865915">"Temizle"</string>
<string name="allow" msgid="8885707816848569619">"İzin ver"</string>
<string name="deny" msgid="6040983710442068936">"Reddet"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index a50fd45..281c8b2 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -41,9 +41,10 @@
<item quantity="many">Ще <xliff:g id="COUNT_1">^1</xliff:g> додаткових елементів</item>
<item quantity="other">Ще <xliff:g id="COUNT_1">^1</xliff:g> додаткового елемента</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Видалити тимчасові файли додатків?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Видалити тимчасові файли додатків"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"Додаток <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> хоче видалити деякі тимчасові файли. Це може збільшити використання акумулятора або мобільного трафіку."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Видалення тимчасових файлів додатків…"</string>
+ <string name="clear" msgid="5524638938415865915">"Очистити"</string>
<string name="allow" msgid="8885707816848569619">"Дозволити"</string>
<string name="deny" msgid="6040983710442068936">"Заборонити"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index fd7e14c..ad6cdf1 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">مزید <xliff:g id="COUNT_1">^1</xliff:g> اضافی آئٹمز</item>
<item quantity="one">مزید <xliff:g id="COUNT_0">^1</xliff:g> اضافی آئٹم</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"ایپ کی عارضی فائلز کو صاف کریں؟"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"ایپ کی عارضی فائلز کو صاف کریں"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> کچھ عارضی فائلز کو صاف کرنا چاہتی ہے۔ اس کی وجہ سے بیٹری یا سیلولر ڈیٹا کے استعمال میں اضافہ ہو سکتا ہے۔"</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"ایپ کی عارضی فائلز کو صاف کیا جا رہا ہے…"</string>
+ <string name="clear" msgid="5524638938415865915">"صاف کریں"</string>
<string name="allow" msgid="8885707816848569619">"اجازت دیں"</string>
<string name="deny" msgid="6040983710442068936">"مسترد کریں"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 982651f..0dcad99 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">Yana <xliff:g id="COUNT_1">^1</xliff:g> ta qoʻshimcha element</item>
<item quantity="one">Yana <xliff:g id="COUNT_0">^1</xliff:g> ta qoʻshimcha element</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Ilovaga oid vaqtincha fayllar tozalansinmi?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Ilovaga oid vaqtincha fayllarni tozalash"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ayrim vaqtincha fayllarni tozalamoqchi. Bunda batareya quvvati yoki internet trafigi ortiqcha sarflanishi mumkin."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Ilovaga oid vaqtincha fayllar tozalanmoqda…"</string>
+ <string name="clear" msgid="5524638938415865915">"Tozalash"</string>
<string name="allow" msgid="8885707816848569619">"Ruxsat"</string>
<string name="deny" msgid="6040983710442068936">"Rad etish"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 5a4ee8c..d0cbec7 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">Và <xliff:g id="COUNT_1">^1</xliff:g> mục khác</item>
<item quantity="one">Và <xliff:g id="COUNT_0">^1</xliff:g> mục khác</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Xóa tệp ứng dụng tạm thời?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Xóa tệp ứng dụng tạm thời"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> muốn xóa một số tệp tạm thời. Điều này có thể làm tăng mức sử dụng pin hoặc dữ liệu di động."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Đang xóa tệp ứng dụng tạm thời…"</string>
+ <string name="clear" msgid="5524638938415865915">"Xóa"</string>
<string name="allow" msgid="8885707816848569619">"Cho phép"</string>
<string name="deny" msgid="6040983710442068936">"Từ chối"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 6d4c467..6cd41f7 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">还有 <xliff:g id="COUNT_1">^1</xliff:g> 项</item>
<item quantity="one">还有 <xliff:g id="COUNT_0">^1</xliff:g> 项</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"要清除临时应用文件吗?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"清除临时应用文件"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>请求清除一些临时文件。这可能消耗更多电量或数据流量。"</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"正在清除临时应用文件…"</string>
+ <string name="clear" msgid="5524638938415865915">"清除"</string>
<string name="allow" msgid="8885707816848569619">"允许"</string>
<string name="deny" msgid="6040983710442068936">"拒绝"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index ffc74ce..3243f9b 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">以及另外 <xliff:g id="COUNT_1">^1</xliff:g> 個項目</item>
<item quantity="one">以及另外 <xliff:g id="COUNT_0">^1</xliff:g> 個項目</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"要清除應用程式暫存檔案嗎?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"清除應用程式暫存檔案"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"「<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>」要求清除部分臨時檔案。這可能會導致耗電量或流動數據用量增加。"</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"正在清除應用程式暫存檔案…"</string>
+ <string name="clear" msgid="5524638938415865915">"清除"</string>
<string name="allow" msgid="8885707816848569619">"允許"</string>
<string name="deny" msgid="6040983710442068936">"拒絕"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index f19f715..1a37210 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -37,9 +37,10 @@
<item quantity="other">還有另外 <xliff:g id="COUNT_1">^1</xliff:g> 個項目</item>
<item quantity="one">還有另外 <xliff:g id="COUNT_0">^1</xliff:g> 個項目</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"要清除應用程式暫存檔案嗎?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"清除應用程式暫存檔案"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"「<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>」想要清除某些暫存檔案,這可能會導致耗電量或行動數據用量增加。"</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"正在清除應用程式暫存檔案…"</string>
+ <string name="clear" msgid="5524638938415865915">"清除"</string>
<string name="allow" msgid="8885707816848569619">"允許"</string>
<string name="deny" msgid="6040983710442068936">"拒絕"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 2fe5245..e2f528d 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -37,9 +37,10 @@
<item quantity="one">Kanye no-<xliff:g id="COUNT_1">^1</xliff:g> izinto ezingeziwe</item>
<item quantity="other">Kanye no-<xliff:g id="COUNT_1">^1</xliff:g> izinto ezingeziwe</item>
</plurals>
- <string name="cache_clearing_dialog_title" msgid="4672878017407595782">"Sula amafayela ohlelo lokusebenza wesikhashana?"</string>
+ <string name="cache_clearing_dialog_title" msgid="8907893815183913664">"Sula amafayela ohlelo lokusebenza wesikhashana"</string>
<string name="cache_clearing_dialog_text" msgid="7057784635111940957">"I-<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ingathanda ukusula amanye amafayela esikhashana. Lokhu kungaholela ekusetshenzisweni kwebhethri okuphezulu noma kwedatha yeselula."</string>
<string name="cache_clearing_in_progress_title" msgid="6902220064511664209">"Isula amafayela wohlelo lokusebenza wesikhashana…"</string>
+ <string name="clear" msgid="5524638938415865915">"Sula"</string>
<string name="allow" msgid="8885707816848569619">"Vumela"</string>
<string name="deny" msgid="6040983710442068936">"Nqaba"</string>
<plurals name="permission_write_audio" formatted="false" msgid="8914759422381305478">
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 28f31ee..ed0c6c2 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -15,5 +15,6 @@
-->
<resources>
- <color name="thumb_gray_color">#1f000000</color>
+ <color name="thumb_gray_color">#1F000000</color>
+ <color name="clear_cache_icon_color">#5F6368</color>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 840135e..c3bdf8f 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -18,4 +18,5 @@
<dimen name="permission_dialog_width">320dp</dimen>
<dimen name="permission_thumb_size">64dp</dimen>
<dimen name="permission_thumb_margin">6dp</dimen>
+ <dimen name="dialog_space">20dp</dimen>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 96c086d..d6171ca 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -62,7 +62,7 @@
</plurals>
<!-- Cache clearing permission dialog warning title. [CHAR LIMIT=NONE] -->
- <string name="cache_clearing_dialog_title">Clear temporary app files?</string>
+ <string name="cache_clearing_dialog_title">Clear temporary app files</string>
<!-- Cache clearing permission dialog warning text. [CHAR LIMIT=NONE] -->
<string name="cache_clearing_dialog_text"><xliff:g id="app_seeking_permission" example="File manager">%s</xliff:g> would like to clear some temporary files. This may result in an increased usage of battery or cellular data.</string>
@@ -70,6 +70,9 @@
<!-- Cache clearing in progress title. [CHAR LIMIT=NONE] -->
<string name="cache_clearing_in_progress_title">Clearing temporary app files\u2026</string>
+ <!-- Cache clearing permission dialog Clear button text. [CHAR LIMIT=30] -->
+ <string name="clear">Clear</string>
+
<!-- Allow dialog action text. [CHAR LIMIT=30] -->
<string name="allow">Allow</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 322ba66..5f1e662 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -16,15 +16,16 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <style name="PickerDialogTheme" parent="@*android:style/Theme.DeviceDefault.Settings.Dialog">
+ <style name="PickerDialogTheme"
+ parent="@android:style/Theme.DeviceDefault.Light.Dialog.Alert">
<item name="android:windowNoTitle">true</item>
</style>
<style name="AlertDialogTheme"
- parent="@*android:style/Theme.DeviceDefault.Dialog.Alert.DayNight" />
+ parent="@android:style/Theme.DeviceDefault.Light.Dialog.Alert"/>
<style name="CacheClearingAlertDialogTheme"
- parent="@*android:style/Theme.DeviceDefault.Dialog.Alert.DayNight">
+ parent="@android:style/Theme.DeviceDefault.Light.Dialog.Alert">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowContentOverlay">@null</item>
@@ -41,6 +42,7 @@
<item name="android:gravity">center</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:textSize">16sp</item>
+ <item name="android:textStyle">bold</item>
</style>
<style name="PermissionAlertDialogTitle"
diff --git a/src/com/android/providers/media/CacheClearingActivity.java b/src/com/android/providers/media/CacheClearingActivity.java
index d65a4a2..e3aff15 100644
--- a/src/com/android/providers/media/CacheClearingActivity.java
+++ b/src/com/android/providers/media/CacheClearingActivity.java
@@ -25,6 +25,7 @@
import android.graphics.Typeface;
import android.os.AsyncTask;
import android.os.Bundle;
+import android.os.Handler;
import android.text.BidiFormatter;
import android.text.SpannableString;
import android.text.TextPaint;
@@ -43,6 +44,7 @@
private static final String TAG = "CacheClearingActivity";
private static final float MAX_APP_NAME_SIZE_PX = 500f;
private static final float TEXT_SIZE = 42f;
+ private static final Long LEAST_SHOW_PROGRESS_TIME_MS = 300L;
private AlertDialog mActionDialog;
private Dialog mLoadingDialog;
@@ -102,11 +104,14 @@
}
private class CacheClearingTask extends AsyncTask<Void, Void, Integer> {
+ private long mStartTime;
+
@Override
protected void onPreExecute() {
dismissDialogs(mActionDialog);
createLoadingDialog();
mLoadingDialog.show();
+ mStartTime = System.currentTimeMillis();
}
@Override
@@ -118,13 +123,25 @@
protected void onPostExecute(Integer result) {
// We take the convention of not using primitive wrapper pretty seriously
int status = result.intValue();
- dismissDialogs(mLoadingDialog);
+
if (result == 0) {
setResult(RESULT_OK);
} else {
setResult(status);
}
- finish();
+
+ // Don't dismiss the progress dialog too quick, it will cause bad UX.
+ final long duration = System.currentTimeMillis() - mStartTime;
+ if (duration > LEAST_SHOW_PROGRESS_TIME_MS) {
+ dismissDialogs(mLoadingDialog);
+ finish();
+ } else {
+ Handler handler = new Handler(getMainLooper());
+ handler.postDelayed(() -> {
+ dismissDialogs(mLoadingDialog);
+ finish();
+ }, LEAST_SHOW_PROGRESS_TIME_MS - duration);
+ }
}
}
@@ -132,12 +149,19 @@
final CharSequence dialogTitle = getString(R.string.cache_clearing_in_progress_title);
final View dialogTitleView = View.inflate(this, R.layout.cache_clearing_dialog, null);
final TextView titleText = dialogTitleView.findViewById(R.id.dialog_title);
+ final ProgressBar progressBar = new ProgressBar(CacheClearingActivity.this);
+ final int padding = getResources().getDimensionPixelOffset(R.dimen.dialog_space);
+
+ progressBar.setIndeterminate(true);
+ progressBar.setPadding(0, padding / 2, 0, padding);
titleText.setText(dialogTitle);
mLoadingDialog = new AlertDialog.Builder(this)
.setCustomTitle(dialogTitleView)
- .setView(new ProgressBar(CacheClearingActivity.this))
+ .setView(progressBar)
.setCancelable(false)
.create();
+
+ dialogTitleView.findViewById(R.id.dialog_icon).setVisibility(View.GONE);
mLoadingDialog.create();
setDialogOverlaySettings(mActionDialog);
}
@@ -149,16 +173,7 @@
final String unsanitizedAppName = TextUtils.ellipsize(appLabel,
paint, MAX_APP_NAME_SIZE_PX, TextUtils.TruncateAt.END).toString();
final String appName = BidiFormatter.getInstance().unicodeWrap(unsanitizedAppName);
-
final String actionText = getString(R.string.cache_clearing_dialog_text, appName);
- final SpannableString message = new SpannableString(actionText);
-
- int appNameIndex = actionText.indexOf(appName);
- if (appNameIndex >= 0) {
- message.setSpan(new StyleSpan(Typeface.BOLD),
- appNameIndex, appNameIndex + appName.length(), 0);
- }
-
final CharSequence dialogTitle = getString(R.string.cache_clearing_dialog_title);
final View dialogTitleView = View.inflate(this, R.layout.cache_clearing_dialog, null);
@@ -166,9 +181,9 @@
titleText.setText(dialogTitle);
mActionDialog = new AlertDialog.Builder(this)
.setCustomTitle(dialogTitleView)
- .setMessage(message)
- .setPositiveButton(R.string.allow, this)
- .setNegativeButton(R.string.deny, this)
+ .setMessage(actionText)
+ .setPositiveButton(R.string.clear, this)
+ .setNegativeButton(android.R.string.cancel, this)
.setCancelable(false)
.create();
diff --git a/src/com/android/providers/media/DatabaseHelper.java b/src/com/android/providers/media/DatabaseHelper.java
index 84ed540..d48726b 100644
--- a/src/com/android/providers/media/DatabaseHelper.java
+++ b/src/com/android/providers/media/DatabaseHelper.java
@@ -160,7 +160,7 @@
@Nullable Class<? extends Annotation> columnAnnotation,
@Nullable OnSchemaChangeListener schemaListener,
@Nullable OnFilesChangeListener filesListener,
- @Nullable OnLegacyMigrationListener migrationListener,
+ @NonNull OnLegacyMigrationListener migrationListener,
@Nullable UnaryOperator<String> idGenerator) {
this(context, name, getDatabaseVersion(context), internal, earlyUpgrade, legacyProvider,
columnAnnotation, schemaListener, filesListener, migrationListener, idGenerator);
@@ -171,7 +171,7 @@
@Nullable Class<? extends Annotation> columnAnnotation,
@Nullable OnSchemaChangeListener schemaListener,
@Nullable OnFilesChangeListener filesListener,
- @Nullable OnLegacyMigrationListener migrationListener,
+ @NonNull OnLegacyMigrationListener migrationListener,
@Nullable UnaryOperator<String> idGenerator) {
super(context, name, null, version);
mContext = context;
@@ -1009,7 +1009,7 @@
+ ", COUNT(DISTINCT album_id) AS " + Audio.Artists.NUMBER_OF_ALBUMS
+ ", COUNT(DISTINCT _id) AS " + Audio.Artists.NUMBER_OF_TRACKS
+ " FROM audio"
- + " WHERE volume_name IN " + filterVolumeNames
+ + " WHERE is_music=1 AND volume_name IN " + filterVolumeNames
+ " GROUP BY artist_id");
db.execSQL("CREATE VIEW audio_albums AS SELECT "
@@ -1026,7 +1026,7 @@
+ ", MAX(year) AS " + Audio.Albums.LAST_YEAR
+ ", NULL AS " + Audio.Albums.ALBUM_ART
+ " FROM audio"
- + " WHERE volume_name IN " + filterVolumeNames
+ + " WHERE is_music=1 AND volume_name IN " + filterVolumeNames
+ " GROUP BY album_id");
db.execSQL("CREATE VIEW audio_genres AS SELECT "
@@ -1290,6 +1290,11 @@
db.execSQL("ALTER TABLE files ADD COLUMN xmp BLOB DEFAULT NULL;");
}
+ private static void updateAudioAlbumId(SQLiteDatabase db, boolean internal) {
+ // We change the logic for generating album id, rescan all audio files
+ db.execSQL("UPDATE files SET date_modified=0 WHERE media_type=2;");
+ }
+
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)) {
@@ -1345,7 +1350,7 @@
static final int VERSION_O = 800;
static final int VERSION_P = 900;
static final int VERSION_Q = 1023;
- static final int VERSION_R = 1114;
+ static final int VERSION_R = 1115;
static final int VERSION_LATEST = VERSION_R;
/**
@@ -1488,6 +1493,9 @@
if (fromVersion < 1114) {
// Empty version bump to ensure triggers are recreated
}
+ if (fromVersion < 1115) {
+ updateAudioAlbumId(db, internal);
+ }
// 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/LocalCallingIdentity.java b/src/com/android/providers/media/LocalCallingIdentity.java
index 9bb8198..4797457 100644
--- a/src/com/android/providers/media/LocalCallingIdentity.java
+++ b/src/com/android/providers/media/LocalCallingIdentity.java
@@ -37,6 +37,7 @@
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 android.annotation.Nullable;
import android.app.AppOpsManager;
@@ -216,6 +217,8 @@
public static final int PERMISSION_WRITE_VIDEO = 1 << 20;
public static final int PERMISSION_WRITE_IMAGES = 1 << 21;
+ public static final int PERMISSION_IS_SYSTEM_GALLERY = 1 <<22;
+
/**
* Explicitly checks **only** for INSTALL_PACKAGES runtime permission.
*/
@@ -290,6 +293,9 @@
case PERMISSION_WRITE_IMAGES:
return checkPermissionWriteImages(
context, pid, uid, getPackageName(), attributionTag);
+ case PERMISSION_IS_SYSTEM_GALLERY:
+ return checkWriteImagesOrVideoAppOps(
+ context, uid, getPackageName(), attributionTag);
case PERMISSION_INSTALL_PACKAGES:
return checkPermissionInstallPackages(
context, pid, uid, getPackageName(), attributionTag);
diff --git a/src/com/android/providers/media/MediaDocumentsProvider.java b/src/com/android/providers/media/MediaDocumentsProvider.java
index f26716d..5121a45 100644
--- a/src/com/android/providers/media/MediaDocumentsProvider.java
+++ b/src/com/android/providers/media/MediaDocumentsProvider.java
@@ -939,7 +939,7 @@
if (mimeTypes == null || !shouldFilterMimeType || matchedMimeTypes.size() > 0) {
final Pair<String, String[]> selectionPair = buildSearchSelection(displayName,
matchedMimeTypes.toArray(new String[0]), lastModifiedAfter,
- fileSizeOver, AudioColumns.TITLE, AudioColumns.MIME_TYPE,
+ fileSizeOver, AudioColumns.DISPLAY_NAME, AudioColumns.MIME_TYPE,
AudioColumns.DATE_MODIFIED, AudioColumns.SIZE);
cursor = resolver.query(Audio.Media.EXTERNAL_CONTENT_URI, SongQuery.PROJECTION,
diff --git a/src/com/android/providers/media/MediaProvider.java b/src/com/android/providers/media/MediaProvider.java
index 035daa1..689ce26 100644
--- a/src/com/android/providers/media/MediaProvider.java
+++ b/src/com/android/providers/media/MediaProvider.java
@@ -47,6 +47,7 @@
import static com.android.providers.media.LocalCallingIdentity.PERMISSION_IS_REDACTION_NEEDED;
import static com.android.providers.media.LocalCallingIdentity.PERMISSION_IS_SELF;
import static com.android.providers.media.LocalCallingIdentity.PERMISSION_IS_SHELL;
+import static com.android.providers.media.LocalCallingIdentity.PERMISSION_IS_SYSTEM_GALLERY;
import static com.android.providers.media.LocalCallingIdentity.PERMISSION_READ_AUDIO;
import static com.android.providers.media.LocalCallingIdentity.PERMISSION_READ_IMAGES;
import static com.android.providers.media.LocalCallingIdentity.PERMISSION_READ_VIDEO;
@@ -57,6 +58,7 @@
import static com.android.providers.media.scan.MediaScanner.REASON_DEMAND;
import static com.android.providers.media.scan.MediaScanner.REASON_IDLE;
import static com.android.providers.media.util.DatabaseUtils.bindList;
+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.extractFileName;
@@ -703,7 +705,9 @@
return null;
};
- private final OnLegacyMigrationListener mMigrationListener = new OnLegacyMigrationListener() {
+ /** {@hide} */
+ public static final OnLegacyMigrationListener MIGRATION_LISTENER =
+ new OnLegacyMigrationListener() {
@Override
public void onStarted(ContentProviderClient client, String volumeName) {
MediaStore.startLegacyMigration(ContentResolver.wrap(client), volumeName);
@@ -770,29 +774,6 @@
}
}
- private static final String[] sDefaultFolderNames = {
- 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_AUDIOBOOKS,
- Environment.DIRECTORY_DOCUMENTS,
- };
-
- private static boolean isDefaultDirectoryName(@Nullable String dirName) {
- for (String defaultDirName : sDefaultFolderNames) {
- if (defaultDirName.equals(dirName)) {
- return true;
- }
- }
- return false;
- }
-
/**
* Ensure that default folders are created on mounted primary storage
* devices. We only do this once per volume so we don't annoy the user if
@@ -817,7 +798,7 @@
final SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(getContext());
if (prefs.getInt(key, 0) == 0) {
- for (String folderName : sDefaultFolderNames) {
+ for (String folderName : DEFAULT_FOLDER_NAMES) {
final File folder = new File(vol.getDirectory(), folderName);
if (!folder.exists()) {
folder.mkdirs();
@@ -904,10 +885,10 @@
mInternalDatabase = new DatabaseHelper(context, INTERNAL_DATABASE_NAME,
true, false, false, Column.class,
- Metrics::logSchemaChange, mFilesListener, mMigrationListener, mIdGenerator);
+ Metrics::logSchemaChange, mFilesListener, MIGRATION_LISTENER, mIdGenerator);
mExternalDatabase = new DatabaseHelper(context, EXTERNAL_DATABASE_NAME,
false, false, false, Column.class,
- Metrics::logSchemaChange, mFilesListener, mMigrationListener, mIdGenerator);
+ Metrics::logSchemaChange, mFilesListener, MIGRATION_LISTENER, mIdGenerator);
final IntentFilter packageFilter = new IntentFilter();
packageFilter.setPriority(10);
@@ -1223,18 +1204,39 @@
@VisibleForTesting
static void computeAudioKeyValues(ContentValues values) {
- computeAudioKeyValue(values,
- AudioColumns.TITLE, AudioColumns.TITLE_KEY, null);
- computeAudioKeyValue(values,
- AudioColumns.ALBUM, AudioColumns.ALBUM_KEY, AudioColumns.ALBUM_ID);
- computeAudioKeyValue(values,
- AudioColumns.ARTIST, AudioColumns.ARTIST_KEY, AudioColumns.ARTIST_ID);
- computeAudioKeyValue(values,
- AudioColumns.GENRE, AudioColumns.GENRE_KEY, AudioColumns.GENRE_ID);
+ computeAudioKeyValue(values, AudioColumns.TITLE, AudioColumns.TITLE_KEY, /* focusId */
+ null, /* hashValue */ 0);
+ computeAudioKeyValue(values, AudioColumns.ARTIST, AudioColumns.ARTIST_KEY,
+ AudioColumns.ARTIST_ID, /* hashValue */ 0);
+ computeAudioKeyValue(values, AudioColumns.GENRE, AudioColumns.GENRE_KEY,
+ AudioColumns.GENRE_ID, /* hashValue */ 0);
+ computeAudioAlbumKeyValue(values);
+ }
+
+ /**
+ * To distinguish same-named albums, we append a hash. The hash is
+ * based on the "album artist" tag if present, otherwise on the path of
+ * the parent directory of the audio file.
+ */
+ private static void computeAudioAlbumKeyValue(ContentValues values) {
+ int hashCode = 0;
+
+ final String albumArtist = values.getAsString(MediaColumns.ALBUM_ARTIST);
+ if (!TextUtils.isEmpty(albumArtist)) {
+ hashCode = albumArtist.hashCode();
+ } else {
+ final String path = values.getAsString(MediaColumns.DATA);
+ if (!TextUtils.isEmpty(path)) {
+ hashCode = path.substring(0, path.lastIndexOf('/')).hashCode();
+ }
+ }
+
+ computeAudioKeyValue(values, AudioColumns.ALBUM, AudioColumns.ALBUM_KEY,
+ AudioColumns.ALBUM_ID, hashCode);
}
private static void computeAudioKeyValue(@NonNull ContentValues values, @NonNull String focus,
- @Nullable String focusKey, @Nullable String focusId) {
+ @Nullable String focusKey, @Nullable String focusId, int hashValue) {
if (focusKey != null) values.remove(focusKey);
if (focusId != null) values.remove(focusId);
@@ -1250,8 +1252,8 @@
if (focusId != null) {
// Many apps break if we generate negative IDs, so trim off the
// highest bit to ensure we're always unsigned
- final long id = Hashing.farmHashFingerprint64()
- .hashString(key, StandardCharsets.UTF_8).asLong() & ~(1L << 63);
+ final long id = Hashing.farmHashFingerprint64().hashString(key + hashValue,
+ StandardCharsets.UTF_8).asLong() & ~(1L << 63);
values.put(focusId, id);
}
}
@@ -1741,15 +1743,17 @@
* Gets all files in the given {@code path} and subdirectories of the given {@code path}.
*/
private ArrayList<String> getAllFilesForRenameDirectory(String oldPath) {
- final String selection = MediaColumns.RELATIVE_PATH + " REGEXP '^" +
- extractRelativePathWithDisplayName(oldPath) + "/?.*' and mime_type not like 'null'";
+ final String selection = FileColumns.DATA + " LIKE ? ESCAPE '\\'"
+ + " and mime_type not like 'null'";
+ final String[] selectionArgs = new String[] {DatabaseUtils.escapeForLike(oldPath) + "/%"};
ArrayList<String> fileList = new ArrayList<>();
final LocalCallingIdentity token = clearLocalCallingIdentity();
try (final Cursor c = query(FileUtils.getContentUriForPath(oldPath),
- new String[] {MediaColumns.DATA}, selection, null, null)) {
+ new String[] {MediaColumns.DATA}, selection, selectionArgs, null)) {
while (c.moveToNext()) {
- final String filePath = c.getString(0).replaceFirst("^" + oldPath + "/(.*)", "$1");
+ String filePath = c.getString(0);
+ filePath = filePath.replaceFirst(Pattern.quote(oldPath + "/"), "");
fileList.add(filePath);
}
} finally {
@@ -1783,13 +1787,15 @@
}
final int countAllFilesInDirectory;
- final String selection = MediaColumns.RELATIVE_PATH + " REGEXP '^" +
- extractRelativePathWithDisplayName(oldPath) + "/?.*' and mime_type not like 'null'";
+ final String selection = FileColumns.DATA + " LIKE ? ESCAPE '\\'"
+ + " and mime_type not like 'null'";
+ final String[] selectionArgs = new String[] {DatabaseUtils.escapeForLike(oldPath) + "/%"};
+
final Uri uriOldPath = FileUtils.getContentUriForPath(oldPath);
final LocalCallingIdentity token = clearLocalCallingIdentity();
- try (final Cursor c = query(uriOldPath, new String[] {MediaColumns._ID}, selection, null,
- null)) {
+ try (final Cursor c = query(uriOldPath, new String[] {MediaColumns._ID}, selection,
+ selectionArgs, null)) {
// get actual number of files in the given directory.
countAllFilesInDirectory = c.getCount();
} finally {
@@ -1809,8 +1815,8 @@
ArrayList<String> fileList = new ArrayList<>();
final String[] projection = {MediaColumns.DATA, MediaColumns.MIME_TYPE};
- try (Cursor c = qb.query(helper, projection, selection, null,
- null, null, null, null, null)) {
+ try (Cursor c = qb.query(helper, projection, selection, selectionArgs, null, null, null,
+ null, null)) {
// Check if the calling package has write permission to all files in the given
// directory. If calling package has write permission to all files in the directory, the
// query with update uri should return same number of files as previous query.
@@ -1819,7 +1825,9 @@
+ " to rename one or more files in " + oldPath);
}
while(c.moveToNext()) {
- final String filePath = c.getString(0).replaceFirst("^" + oldPath + "/(.*)", "$1");
+ String filePath = c.getString(0);
+ filePath = filePath.replaceFirst(Pattern.quote(oldPath + "/"), "");
+
final String mimeType = c.getString(1);
if (!isMimeTypeSupportedInPath(newPath + "/" + filePath, mimeType)) {
throw new IllegalArgumentException("Can't rename " + oldPath + "/" + filePath
@@ -2061,6 +2069,10 @@
return OsConstants.EPERM;
}
+ if (shouldBypassDatabaseForFuse(uid)) {
+ return renameInLowerFs(oldPath, newPath);
+ }
+
if (shouldBypassFuseRestrictions(/*forWrite*/ true, oldPath)
&& shouldBypassFuseRestrictions(/*forWrite*/ true, newPath)) {
return renameUncheckedForFuse(oldPath, newPath);
@@ -2077,17 +2089,19 @@
// Rename not allowed on paths that can't be translated to RELATIVE_PATH.
Log.e(TAG, errorMessage + "Invalid path.");
return OsConstants.EPERM;
- } else if (oldRelativePath.length == 1 && TextUtils.isEmpty(oldRelativePath[0])) {
+ }
+ if (oldRelativePath.length == 1 && TextUtils.isEmpty(oldRelativePath[0])) {
// Allow rename of files/folders other than default directories.
final String displayName = extractDisplayName(oldPath);
- for (String defaultFolder : sDefaultFolderNames) {
+ for (String defaultFolder : DEFAULT_FOLDER_NAMES) {
if (displayName.equals(defaultFolder)) {
Log.e(TAG, errorMessage + oldPath + " is a default folder."
+ " Renaming a default folder is not allowed.");
return OsConstants.EPERM;
}
}
- } else if (newRelativePath.length == 1 && TextUtils.isEmpty(newRelativePath[0])) {
+ }
+ if (newRelativePath.length == 1 && TextUtils.isEmpty(newRelativePath[0])) {
Log.e(TAG, errorMessage + newPath + " is in root folder."
+ " Renaming a file/directory to root folder is not allowed");
return OsConstants.EPERM;
@@ -2150,10 +2164,13 @@
}
final int type;
+ final boolean forWrite;
if ((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
type = TYPE_UPDATE;
+ forWrite = true;
} else {
type = TYPE_QUERY;
+ forWrite = false;
}
final SQLiteQueryBuilder qb = getQueryBuilder(type, table, uri, Bundle.EMPTY, null);
@@ -2163,6 +2180,24 @@
return PackageManager.PERMISSION_GRANTED;
}
}
+
+ try {
+ if (ContentUris.parseId(uri) != -1) {
+ return PackageManager.PERMISSION_DENIED;
+ }
+ } catch (NumberFormatException ignored) { }
+
+ // If the uri is a valid content uri and doesn't have a valid ID at the end of the uri,
+ // (i.e., uri is uri of the table not of the item/row), and app doesn't request prefix
+ // grant, we are willing to grant this uri permission since this doesn't grant them any
+ // extra access. This grant will only grant permissions on given uri, it will not grant
+ // access to db rows of the corresponding table.
+ if ((modeFlags & Intent.FLAG_GRANT_PREFIX_URI_PERMISSION) == 0) {
+ return PackageManager.PERMISSION_GRANTED;
+ }
+
+ // For prefix grant on the uri with content uri without id, we don't allow apps to
+ // grant access as they might end up granting access to all files.
} finally {
restoreLocalCallingIdentity(token);
}
@@ -2572,17 +2607,17 @@
defaultMimeType = "audio/mpegurl";
defaultMediaType = FileColumns.MEDIA_TYPE_PLAYLIST;
defaultPrimary = Environment.DIRECTORY_MUSIC;
- allowedPrimary = Arrays.asList(
- Environment.DIRECTORY_MUSIC,
- Environment.DIRECTORY_MOVIES);
+ allowedPrimary = new ArrayList<>(allowedPrimary);
+ allowedPrimary.add(Environment.DIRECTORY_MUSIC);
+ allowedPrimary.add(Environment.DIRECTORY_MOVIES);
break;
case FileColumns.MEDIA_TYPE_SUBTITLE:
defaultMimeType = "application/x-subrip";
defaultMediaType = FileColumns.MEDIA_TYPE_SUBTITLE;
defaultPrimary = Environment.DIRECTORY_MOVIES;
- allowedPrimary = Arrays.asList(
- Environment.DIRECTORY_MUSIC,
- Environment.DIRECTORY_MOVIES);
+ allowedPrimary = new ArrayList<>(allowedPrimary);
+ allowedPrimary.add(Environment.DIRECTORY_MUSIC);
+ allowedPrimary.add(Environment.DIRECTORY_MOVIES);
break;
}
} else if (defaultMediaType != actualMediaType) {
@@ -3078,7 +3113,11 @@
if (isCallingPackageSelf() && values.containsKey(FileColumns.MEDIA_TYPE)) {
// Leave FileColumns.MEDIA_TYPE untouched if the caller is ModernMediaScanner and
// FileColumns.MEDIA_TYPE is already populated.
- } else if (path != null && shouldFileBeHidden(new File(path))) {
+ } else if (isFuseThread() && path != null && shouldFileBeHidden(new File(path))) {
+ // We should only mark MEDIA_TYPE as MEDIA_TYPE_NONE for Fuse Thread.
+ // MediaProvider#insert() returns the uri by appending the "rowId" to the given
+ // uri, hence to ensure the correct working of the returned uri, we shouldn't
+ // change the MEDIA_TYPE in insert operation and let scan change it for us.
values.put(FileColumns.MEDIA_TYPE, FileColumns.MEDIA_TYPE_NONE);
} else {
values.put(FileColumns.MEDIA_TYPE, MimeUtils.resolveMediaType(mimeType));
@@ -3367,6 +3406,9 @@
if (isCallingPackageSelf() || isCallingPackageLegacyWrite()) {
// Mutation allowed
+ } else if (isCallingPackageManager()) {
+ // Apps with MANAGE_EXTERNAL_STORAGE have all files access, hence they are
+ // allowed to insert files anywhere.
} else {
Log.w(TAG, "Ignoring mutation of " + column + " from "
+ getCallingPackageOrSelf());
@@ -3387,6 +3429,15 @@
if (initialValues.containsKey(ImageColumns.LONGITUDE)) {
initialValues.putNull(ImageColumns.LONGITUDE);
}
+ if (getCallingPackageTargetSdkVersion() <= Build.VERSION_CODES.Q) {
+ // These columns are removed in R.
+ if (initialValues.containsKey("primary_directory")) {
+ initialValues.remove("primary_directory");
+ }
+ if (initialValues.containsKey("secondary_directory")) {
+ initialValues.remove("secondary_directory");
+ }
+ }
if (isCallingPackageSelf() || isCallingPackageShell()) {
// When media inserted by ourselves during a scan, or by the
@@ -4009,7 +4060,7 @@
case AUDIO_ARTISTS_ID_ALBUMS: {
if (type == TYPE_QUERY) {
qb.setTables("audio_albums");
- qb.setProjectionMap(getProjectionMap(Audio.Artists.Albums.class));
+ qb.setProjectionMap(getProjectionMap(Audio.Albums.class));
final String artistId = uri.getPathSegments().get(3);
appendWhereStandalone(qb, "artist_id=?", artistId);
@@ -5221,6 +5272,15 @@
if (initialValues.containsKey(ImageColumns.LONGITUDE)) {
initialValues.putNull(ImageColumns.LONGITUDE);
}
+ if (getCallingPackageTargetSdkVersion() <= Build.VERSION_CODES.Q) {
+ // These columns are removed in R.
+ if (initialValues.containsKey("primary_directory")) {
+ initialValues.remove("primary_directory");
+ }
+ if (initialValues.containsKey("secondary_directory")) {
+ initialValues.remove("secondary_directory");
+ }
+ }
}
// If we're not updating anything, then we can skip
@@ -6098,6 +6158,8 @@
// the remote writer tried claiming an exception
invalidateThumbnails(uri);
+ // Invalidate so subsequent stat(2) on the upper fs is eventually consistent
+ invalidateFuseDentry(file);
try {
switch (match) {
case IMAGES_THUMBNAILS_ID:
@@ -6331,6 +6393,24 @@
return !isCallingIdentitySharedPackageName(appSpecificDir);
}
+ private boolean shouldBypassDatabaseForFuse(int uid) {
+ final LocalCallingIdentity token =
+ clearLocalCallingIdentity(getCachedCallingIdentityForFuse(uid));
+ try {
+ if (uid != android.os.Process.SHELL_UID && isCallingPackageManager()) {
+ return true;
+ }
+ // We bypass db operations for legacy system galleries with W_E_S (see b/167307393).
+ // Tracking a longer term solution in b/168784136.
+ if (isCallingPackageLegacyWrite() && isCallingPackageSystemGallery()) {
+ return true;
+ }
+ return false;
+ } finally {
+ restoreLocalCallingIdentity(token);
+ }
+ }
+
/**
* Set of Exif tags that should be considered for redaction.
*/
@@ -6759,6 +6839,10 @@
return OsConstants.EPERM;
}
+ if (shouldBypassDatabaseForFuse(uid)) {
+ return 0;
+ }
+
final String mimeType = MimeUtils.resolveMimeType(new File(path));
if (shouldBypassFuseRestrictions(/*forWrite*/ true, path)) {
@@ -6867,6 +6951,10 @@
return OsConstants.ENOENT;
}
+ if (shouldBypassDatabaseForFuse(uid)) {
+ return deleteFileUnchecked(path);
+ }
+
final boolean shouldBypass = shouldBypassFuseRestrictions(/*forWrite*/ true, path);
// Legacy apps that made is this far don't have the right storage permission and hence
@@ -6942,7 +7030,7 @@
if (isTopLevelDir) {
// We allow creating the default top level directories only, all other operations on
// top level directories are not allowed.
- if (forCreate && isDefaultDirectoryName(extractDisplayName(path))) {
+ if (forCreate && FileUtils.isDefaultDirectoryName(extractDisplayName(path))) {
return 0;
}
Log.e(TAG,
@@ -7007,7 +7095,7 @@
final boolean isTopLevelDir =
relativePath.length == 1 && TextUtils.isEmpty(relativePath[0]);
if (isTopLevelDir) {
- if (isDefaultDirectoryName(extractDisplayName(path))) {
+ if (FileUtils.isDefaultDirectoryName(extractDisplayName(path))) {
return 0;
} else {
Log.e(TAG,
@@ -7850,6 +7938,10 @@
return builder.build();
}
+ private boolean isCallingPackageSystemGallery() {
+ return mCallingIdentity.get().hasPermission(PERMISSION_IS_SYSTEM_GALLERY);
+ }
+
private int getCallingUidOrSelf() {
return mCallingIdentity.get().uid;
}
diff --git a/src/com/android/providers/media/MediaUpgradeReceiver.java b/src/com/android/providers/media/MediaUpgradeReceiver.java
index b9fba09..5864b78 100644
--- a/src/com/android/providers/media/MediaUpgradeReceiver.java
+++ b/src/com/android/providers/media/MediaUpgradeReceiver.java
@@ -67,8 +67,8 @@
try {
DatabaseHelper helper = new DatabaseHelper(
context, file, MediaProvider.isInternalMediaDatabaseName(file),
- false, false, Column.class, Metrics::logSchemaChange, null, null,
- null);
+ false, false, Column.class, Metrics::logSchemaChange, null,
+ MediaProvider.MIGRATION_LISTENER, null);
helper.runWithTransaction((db) -> {
// Perform just enough to force database upgrade
return db.getVersion();
diff --git a/src/com/android/providers/media/PermissionActivity.java b/src/com/android/providers/media/PermissionActivity.java
index 1b2d0ad..6a3cced 100644
--- a/src/com/android/providers/media/PermissionActivity.java
+++ b/src/com/android/providers/media/PermissionActivity.java
@@ -41,6 +41,8 @@
import android.graphics.ImageDecoder;
import android.graphics.ImageDecoder.ImageInfo;
import android.graphics.ImageDecoder.Source;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
@@ -68,9 +70,11 @@
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
+import java.util.function.ToIntFunction;
import java.util.stream.Collectors;
/**
@@ -114,6 +118,12 @@
private static final String DATA_IMAGE = "image";
private static final String DATA_GENERIC = "generic";
+ // Use to sort the thumbnails.
+ private static final int ORDER_IMAGE = 1;
+ private static final int ORDER_VIDEO = 2;
+ private static final int ORDER_AUDIO = 3;
+ private static final int ORDER_GENERIC = 4;
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -497,6 +507,25 @@
}
}
+ // Sort the uris in DATA_GENERIC case (Image, Video, Audio, Others)
+ if (TextUtils.equals(data, DATA_GENERIC) && uris.size() > 1) {
+ final ToIntFunction<Uri> score = (uri) -> {
+ final LocalUriMatcher matcher = new LocalUriMatcher(MediaStore.AUTHORITY);
+ final int match = matcher.matchUri(uri, false);
+
+ switch (match) {
+ case AUDIO_MEDIA_ID: return ORDER_AUDIO;
+ case VIDEO_MEDIA_ID: return ORDER_VIDEO;
+ case IMAGES_MEDIA_ID: return ORDER_IMAGE;
+ default: return ORDER_GENERIC;
+ }
+ };
+ final Comparator<Uri> bestScore = (a, b) ->
+ score.applyAsInt(a) - score.applyAsInt(b);
+
+ uris.sort(bestScore);
+ }
+
for (Uri uri : uris) {
try {
final Description desc = new Description(bodyView.getContext(), uri, loadFlags);
@@ -539,15 +568,23 @@
}
/**
- * Bind dialog as a single full-bleed image.
+ * Bind dialog as a single full-bleed image. If there is no image, use
+ * the icon of Mime type instead.
*/
private void bindAsFull(@NonNull Description result) {
final ImageView thumbFull = bodyView.requireViewById(R.id.thumb_full);
- result.bindFull(thumbFull);
+ if (result.full != null) {
+ result.bindFull(thumbFull);
+ } else {
+ thumbFull.setScaleType(ImageView.ScaleType.FIT_CENTER);
+ thumbFull.setBackground(new ColorDrawable(getColor(R.color.thumb_gray_color)));
+ result.bindMimeIcon(thumbFull);
+ }
}
/**
- * Bind dialog as a list of multiple thumbnails.
+ * Bind dialog as a list of multiple thumbnails. If there is no thumbnail for some
+ * items, use the icons of the MIME type instead.
*/
private void bindAsThumbs(@NonNull List<Description> results,
@NonNull List<Description> visualResults) {
@@ -564,6 +601,7 @@
final View thumbMoreContainer = bodyView.requireViewById(R.id.thumb_more_container);
final ImageView thumbMore = bodyView.requireViewById(R.id.thumb_more);
final TextView thumbMoreText = bodyView.requireViewById(R.id.thumb_more_text);
+ final View gradientView = bodyView.requireViewById(R.id.thumb_more_gradient);
// Since we only want three tiles displayed maximum, swap out
// the first tile for our "more" tile
@@ -577,6 +615,7 @@
thumbMoreText.setText(moreText);
thumbMoreContainer.setVisibility(View.VISIBLE);
+ gradientView.setVisibility(View.VISIBLE);
}
// Trim off extra thumbnails from the front of our list, so that we
@@ -589,7 +628,11 @@
for (int i = 0; i < thumbs.size(); i++) {
final Description desc = visualResults.get(i);
final ImageView imageView = thumbs.get(i);
- desc.bindThumbnail(imageView);
+ if (desc.thumbnail != null) {
+ desc.bindThumbnail(imageView);
+ } else {
+ desc.bindMimeIcon(imageView);
+ }
}
}
@@ -624,6 +667,7 @@
public @Nullable CharSequence contentDescription;
public @Nullable Bitmap thumbnail;
public @Nullable Bitmap full;
+ public @Nullable Icon mimeIcon;
public static final int LOAD_CONTENT_DESCRIPTION = 1 << 0;
public static final int LOAD_THUMBNAIL = 1 << 1;
@@ -662,11 +706,15 @@
}
} catch (IOException e) {
Log.w(TAG, e);
+ if (thumbnail == null && full == null) {
+ final String mimeType = resolver.getType(uri);
+ mimeIcon = resolver.getTypeInfo(mimeType).getIcon();
+ }
}
}
public boolean isVisual() {
- return thumbnail != null || full != null;
+ return thumbnail != null || full != null || mimeIcon != null;
}
public void bindThumbnail(ImageView imageView) {
@@ -683,6 +731,14 @@
imageView.setContentDescription(contentDescription);
imageView.setVisibility(View.VISIBLE);
}
+
+ public void bindMimeIcon(ImageView imageView) {
+ Objects.requireNonNull(mimeIcon);
+ imageView.setImageIcon(mimeIcon);
+ imageView.setContentDescription(contentDescription);
+ imageView.setVisibility(View.VISIBLE);
+ imageView.setClipToOutline(true);
+ }
}
/**
diff --git a/src/com/android/providers/media/scan/ModernMediaScanner.java b/src/com/android/providers/media/scan/ModernMediaScanner.java
index 88cf60b..33a611b 100644
--- a/src/com/android/providers/media/scan/ModernMediaScanner.java
+++ b/src/com/android/providers/media/scan/ModernMediaScanner.java
@@ -421,7 +421,7 @@
new String[] {pathEscapedForLike + "/%", pathEscapedForLike});
queryArgs.putString(ContentResolver.QUERY_ARG_SQL_SORT_ORDER,
FileColumns._ID + " DESC");
- queryArgs.putInt(MediaStore.QUERY_ARG_MATCH_PENDING, MediaStore.MATCH_INCLUDE);
+ queryArgs.putInt(MediaStore.QUERY_ARG_MATCH_PENDING, MediaStore.MATCH_EXCLUDE);
queryArgs.putInt(MediaStore.QUERY_ARG_MATCH_TRASHED, MediaStore.MATCH_INCLUDE);
queryArgs.putInt(MediaStore.QUERY_ARG_MATCH_FAVORITE, MediaStore.MATCH_INCLUDE);
diff --git a/src/com/android/providers/media/util/FileUtils.java b/src/com/android/providers/media/util/FileUtils.java
index 29245d3..d100e57 100644
--- a/src/com/android/providers/media/util/FileUtils.java
+++ b/src/com/android/providers/media/util/FileUtils.java
@@ -914,6 +914,21 @@
private static final Pattern PATTERN_OBB_OR_CHILD_RELATIVE_PATH = Pattern.compile(
"(?i)^Android/obb(?:/.*)?$");
+ @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,
+ };
+
/**
* Regex that matches paths for {@link MediaColumns#RELATIVE_PATH}; it
* captures both top-level paths and sandboxed paths.
@@ -927,6 +942,9 @@
private static final Pattern PATTERN_VOLUME_NAME = Pattern.compile(
"(?i)^/storage/([^/]+)");
+ private static final String CAMERA_RELATIVE_PATH =
+ String.format("%s/%s/", Environment.DIRECTORY_DCIM, "Camera");
+
private static @Nullable String normalizeUuid(@Nullable String fsUuid) {
return fsUuid != null ? fsUuid.toLowerCase(Locale.ROOT) : null;
}
@@ -1073,6 +1091,15 @@
return relativePathSegments.length > 0 ? relativePathSegments[0] : null;
}
+ public static boolean isDefaultDirectoryName(@Nullable String dirName) {
+ for (String defaultDirName : DEFAULT_FOLDER_NAMES) {
+ if (defaultDirName.equalsIgnoreCase(dirName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Compute the value of {@link MediaColumns#DATE_EXPIRES} based on other
* columns being modified by this operation.
@@ -1287,12 +1314,32 @@
}
final File nomedia = new File(dir, ".nomedia");
+
// check for .nomedia presence
- if (nomedia.exists()) {
- Logging.logPersistent("Observed non-standard " + nomedia);
- return true;
+ if (!nomedia.exists()) {
+ return false;
}
- return false;
+
+ // Handle top-level default directories. These directories should always be visible,
+ // regardless of .nomedia presence.
+ final String[] relativePath = sanitizePath(extractRelativePath(dir.getAbsolutePath()));
+ final boolean isTopLevelDir =
+ relativePath.length == 1 && TextUtils.isEmpty(relativePath[0]);
+ if (isTopLevelDir && isDefaultDirectoryName(name)) {
+ nomedia.delete();
+ return false;
+ }
+
+ // DCIM/Camera should always be visible regardless of .nomedia presence.
+ if (CAMERA_RELATIVE_PATH.equalsIgnoreCase(
+ extractRelativePathWithDisplayName(dir.getAbsolutePath()))) {
+ nomedia.delete();
+ return false;
+ }
+
+ // .nomedia is present which makes this directory as hidden directory
+ Logging.logPersistent("Observed non-standard " + nomedia);
+ return true;
}
/**
diff --git a/src/com/android/providers/media/util/PermissionUtils.java b/src/com/android/providers/media/util/PermissionUtils.java
index 4c27624..6b93b48 100644
--- a/src/com/android/providers/media/util/PermissionUtils.java
+++ b/src/com/android/providers/media/util/PermissionUtils.java
@@ -189,6 +189,20 @@
}
/**
+ * Returns {@code true} if the given package has write images or write video app op, which
+ * indicates the package is a system gallery.
+ */
+ public static boolean checkWriteImagesOrVideoAppOps(@NonNull Context context, int uid,
+ @NonNull String packageName, @Nullable String attributionTag) {
+ return checkAppOp(
+ context, OPSTR_WRITE_MEDIA_IMAGES, uid, packageName, attributionTag,
+ generateAppOpMessage(packageName, sOpDescription.get()))
+ || checkAppOp(
+ context, OPSTR_WRITE_MEDIA_VIDEO, uid, packageName, attributionTag,
+ generateAppOpMessage(packageName, sOpDescription.get()));
+ }
+
+ /**
* Returns {@code true} if any package for the given uid has request_install_packages app op.
*/
public static boolean checkAppOpRequestInstallPackagesForSharedUid(@NonNull Context context,
@@ -202,26 +216,6 @@
return false;
}
- /**
- * Checks *only* App Ops.
- */
- private static boolean checkAppOp(@NonNull Context context,
- @NonNull String op, int uid, @NonNull String packageName,
- @Nullable String attributionTag, @Nullable String opMessage) {
- final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
- final int mode = appOps.noteOpNoThrow(op, uid, packageName, attributionTag, opMessage);
- switch (mode) {
- case AppOpsManager.MODE_ALLOWED:
- return true;
- case AppOpsManager.MODE_DEFAULT:
- case AppOpsManager.MODE_IGNORED:
- case AppOpsManager.MODE_ERRORED:
- return false;
- default:
- throw new IllegalStateException(op + " has unknown mode " + mode);
- }
- }
-
public static boolean checkPermissionInstallPackages(@NonNull Context context, int pid, int uid,
@NonNull String packageName, @Nullable String attributionTag) {
return checkPermissionForDataDelivery(context, INSTALL_PACKAGES, pid,
@@ -272,6 +266,27 @@
}
/**
+ * Checks *only* App Ops.
+ */
+ private static boolean checkAppOp(@NonNull Context context,
+ @NonNull String op, int uid, @NonNull String packageName,
+ @Nullable String attributionTag, @Nullable String opMessage) {
+ final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
+ final int mode = appOps.noteOpNoThrow(op, uid, packageName, attributionTag, opMessage);
+ switch (mode) {
+ case AppOpsManager.MODE_ALLOWED:
+ return true;
+ case AppOpsManager.MODE_DEFAULT:
+ case AppOpsManager.MODE_IGNORED:
+ case AppOpsManager.MODE_ERRORED:
+ return false;
+ default:
+ throw new IllegalStateException(op + " has unknown mode " + mode);
+ }
+ }
+
+
+ /**
* Checks *only* App Ops, also returns true for legacy apps.
*/
private static boolean checkAppOpAllowingLegacy(@NonNull Context context,
diff --git a/src/com/android/providers/media/util/SQLiteQueryBuilder.java b/src/com/android/providers/media/util/SQLiteQueryBuilder.java
index e95d28c..e68cb80 100644
--- a/src/com/android/providers/media/util/SQLiteQueryBuilder.java
+++ b/src/com/android/providers/media/util/SQLiteQueryBuilder.java
@@ -75,6 +75,7 @@
+ "mov|asf|avi|divx|mpg|mpeg|mkv|webm|mk3d|mks|3gp|mpegts|ts|m2ts|m2t)");
private static final Pattern sPattern156832140 = Pattern.compile(
"(?i)%com\\.gopro\\.smarty%");
+ private static final Pattern sPattern158537159 = Pattern.compile("(?i)localized");
private static final Pattern sCustomCollatorPattern = Pattern.compile(
"(?i)custom_[a-zA-Z]+");
@@ -817,6 +818,7 @@
// proper SQL string substitution
if (sPattern154193772.matcher(token).matches()) return;
if (sPattern156832140.matcher(token).matches()) return;
+ if (sPattern158537159.matcher(token).matches()) return;
}
throw new IllegalArgumentException("Invalid token " + token);
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 0c1fc65..1a94ef1 100644
--- a/tests/client/src/com/android/providers/media/client/LegacyProviderMigrationTest.java
+++ b/tests/client/src/com/android/providers/media/client/LegacyProviderMigrationTest.java
@@ -49,6 +49,7 @@
import android.webkit.MimeTypeMap;
import androidx.annotation.NonNull;
+import androidx.test.filters.FlakyTest;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
@@ -78,6 +79,7 @@
* {@link MediaColumns#IS_FAVORITE} should be retained.
*/
@RunWith(AndroidJUnit4.class)
+@FlakyTest(bugId = 176977253)
public class LegacyProviderMigrationTest {
private static final String TAG = "LegacyTest";
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 1e1abe7..eff8e67 100644
--- a/tests/client/src/com/android/providers/media/client/PerformanceTest.java
+++ b/tests/client/src/com/android/providers/media/client/PerformanceTest.java
@@ -39,7 +39,6 @@
import org.junit.runner.RunWith;
import java.io.File;
-import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
@@ -367,6 +366,7 @@
public static class CountingContentObserver extends ContentObserver {
private final int uriCount;
private final int flags;
+ private int accumulatedCount = 0;
private final CountDownLatch latch = new CountDownLatch(1);
@@ -381,8 +381,19 @@
Log.v(TAG, String.format("onChange(%b, %s, %d)",
selfChange, asSet(uris).toString(), flags));
- if ((asSet(uris).size() == this.uriCount) && (flags == this.flags)) {
- latch.countDown();
+ if (this.uriCount == 1) {
+ if (asSet(uris).size() == 1 && flags == this.flags) {
+ latch.countDown();
+ }
+ } else if (flags == this.flags) {
+ // NotifyChange for bulk operations will be sent in batches.
+ final int receivedCount = asSet(uris).size();
+
+ if (receivedCount + accumulatedCount == this.uriCount) {
+ latch.countDown();
+ } else {
+ accumulatedCount += receivedCount;
+ }
}
}
diff --git a/tests/src/com/android/providers/media/DatabaseHelperTest.java b/tests/src/com/android/providers/media/DatabaseHelperTest.java
index d57ffe9..b2b7825 100644
--- a/tests/src/com/android/providers/media/DatabaseHelperTest.java
+++ b/tests/src/com/android/providers/media/DatabaseHelperTest.java
@@ -20,6 +20,8 @@
import static com.android.providers.media.DatabaseHelper.makePristineSchema;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
@@ -42,11 +44,12 @@
import com.android.providers.media.scan.MediaScannerTest.IsolatedContext;
+import com.google.common.collect.ImmutableSet;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.Arrays;
import java.util.Set;
@RunWith(AndroidJUnit4.class)
@@ -83,6 +86,7 @@
values.put(AudioColumns.ALBUM, "A Rush of Blood");
values.put(AudioColumns.ARTIST, "Coldplay");
values.put(AudioColumns.GENRE, "Rock");
+ values.put(AudioColumns.IS_MUSIC, true);
MediaProvider.computeAudioKeyValues(values);
db.insert("files", FileColumns.DATA, values);
}
@@ -95,6 +99,7 @@
values.put(AudioColumns.ALBUM, "X&Y");
values.put(AudioColumns.ARTIST, "Coldplay");
values.put(AudioColumns.GENRE, "Alternative rock");
+ values.put(AudioColumns.IS_MUSIC, true);
MediaProvider.computeAudioKeyValues(values);
db.insert("files", FileColumns.DATA, values);
}
@@ -107,48 +112,108 @@
values.put(AudioColumns.ALBUM, "All That You Can't Leave Behind");
values.put(AudioColumns.ARTIST, "U2");
values.put(AudioColumns.GENRE, "Rock");
+ values.put(AudioColumns.IS_MUSIC, true);
MediaProvider.computeAudioKeyValues(values);
db.insert("files", FileColumns.DATA, values);
}
// Confirm that raw view knows everything
- assertEquals(asSet("Clocks", "Speed of Sound", "Beautiful Day"),
- queryValues(helper, "audio", "title"));
+ assertThat(queryValues(helper, "audio", "title"))
+ .containsExactly("Clocks", "Speed of Sound", "Beautiful Day");
// By default, database only knows about primary storage
- assertEquals(asSet("Coldplay"),
- queryValues(helper, "audio_artists", "artist"));
- assertEquals(asSet("A Rush of Blood"),
- queryValues(helper, "audio_albums", "album"));
- assertEquals(asSet("Rock"),
- queryValues(helper, "audio_genres", "name"));
+ assertThat(queryValues(helper, "audio_artists", "artist"))
+ .containsExactly("Coldplay");
+ assertThat(queryValues(helper, "audio_albums", "album"))
+ .containsExactly("A Rush of Blood");
+ assertThat(queryValues(helper, "audio_genres", "name"))
+ .containsExactly("Rock");
// Once we broaden mounted volumes, we know a lot more
- helper.setFilterVolumeNames(asSet(VOLUME_EXTERNAL_PRIMARY, "0000-0000"));
- assertEquals(asSet("Coldplay", "U2"),
- queryValues(helper, "audio_artists", "artist"));
- assertEquals(asSet("A Rush of Blood", "X&Y", "All That You Can't Leave Behind"),
- queryValues(helper, "audio_albums", "album"));
- assertEquals(asSet("Rock", "Alternative rock"),
- queryValues(helper, "audio_genres", "name"));
+ helper.setFilterVolumeNames(ImmutableSet.of(VOLUME_EXTERNAL_PRIMARY, "0000-0000"));
+ assertThat(queryValues(helper, "audio_artists", "artist"))
+ .containsExactly("Coldplay", "U2");
+ assertThat(queryValues(helper, "audio_albums", "album"))
+ .containsExactly("A Rush of Blood", "X&Y", "All That You Can't Leave Behind");
+ assertThat(queryValues(helper, "audio_genres", "name"))
+ .containsExactly("Rock", "Alternative rock");
// And unmounting primary narrows us the other way
- helper.setFilterVolumeNames(asSet("0000-0000"));
- assertEquals(asSet("Coldplay", "U2"),
- queryValues(helper, "audio_artists", "artist"));
- assertEquals(asSet("X&Y", "All That You Can't Leave Behind"),
- queryValues(helper, "audio_albums", "album"));
- assertEquals(asSet("Rock", "Alternative rock"),
- queryValues(helper, "audio_genres", "name"));
+ helper.setFilterVolumeNames(ImmutableSet.of("0000-0000"));
+ assertThat(queryValues(helper, "audio_artists", "artist"))
+ .containsExactly("Coldplay", "U2");
+ assertThat(queryValues(helper, "audio_albums", "album"))
+ .containsExactly("X&Y", "All That You Can't Leave Behind");
+ assertThat(queryValues(helper, "audio_genres", "name"))
+ .containsExactly("Rock", "Alternative rock");
// Finally fully unmounted means nothing
- helper.setFilterVolumeNames(asSet());
- assertEquals(asSet(),
- queryValues(helper, "audio_artists", "artist"));
- assertEquals(asSet(),
- queryValues(helper, "audio_albums", "album"));
- assertEquals(asSet(),
- queryValues(helper, "audio_genres", "name"));
+ helper.setFilterVolumeNames(ImmutableSet.of());
+ assertThat(queryValues(helper, "audio_artists", "artist")).isEmpty();
+ assertThat(queryValues(helper, "audio_albums", "album")).isEmpty();
+ assertThat(queryValues(helper, "audio_genres", "name")).isEmpty();
+ }
+ }
+
+ @Test
+ public void testArtistsAndAlbumsIncludeOnlyMusic() throws Exception {
+ try (DatabaseHelper helper = new DatabaseHelperR(sIsolatedContext, TEST_CLEAN_DB)) {
+ SQLiteDatabase db = helper.getWritableDatabaseForTest();
+ {
+ final ContentValues values = new ContentValues();
+ values.put(FileColumns.MEDIA_TYPE, FileColumns.MEDIA_TYPE_AUDIO);
+ values.put(FileColumns.VOLUME_NAME, VOLUME_EXTERNAL_PRIMARY);
+ values.put(FileColumns.DATA, "/storage/emulated/0/Coldplay-Clocks.mp3");
+ values.put(AudioColumns.TITLE, "Clocks");
+ values.put(AudioColumns.ALBUM, "A Rush of Blood");
+ values.put(AudioColumns.ARTIST, "Coldplay");
+ values.put(AudioColumns.GENRE, "Rock");
+ values.put(AudioColumns.IS_MUSIC, true);
+ MediaProvider.computeAudioKeyValues(values);
+ db.insert("files", FileColumns.DATA, values);
+ }
+ {
+ final ContentValues values = new ContentValues();
+ values.put(FileColumns.MEDIA_TYPE, FileColumns.MEDIA_TYPE_AUDIO);
+ values.put(FileColumns.VOLUME_NAME, VOLUME_EXTERNAL_PRIMARY);
+ values.put(FileColumns.DATA, "/storage/emulated/0/My-podcast.mp3");
+ values.put(AudioColumns.TITLE, "My podcast title with false is_music");
+ values.put(AudioColumns.ALBUM, "My podcast album");
+ values.put(AudioColumns.ARTIST, "My podcast artist");
+ values.put(AudioColumns.GENRE, "Podcast");
+ values.put(AudioColumns.IS_MUSIC, false);
+ MediaProvider.computeAudioKeyValues(values);
+ db.insert("files", FileColumns.DATA, values);
+ }
+ {
+ final ContentValues values = new ContentValues();
+ values.put(FileColumns.MEDIA_TYPE, FileColumns.MEDIA_TYPE_AUDIO);
+ values.put(FileColumns.VOLUME_NAME, VOLUME_EXTERNAL_PRIMARY);
+ values.put(FileColumns.DATA, "/storage/emulated/0/My-podcast-2.mp3");
+ values.put(AudioColumns.TITLE, "My podcast title with not set is_music");
+ values.put(AudioColumns.ALBUM, "My podcast album");
+ values.put(AudioColumns.ARTIST, "My podcast artist");
+ values.put(AudioColumns.GENRE, "Podcast 2");
+ MediaProvider.computeAudioKeyValues(values);
+ db.insert("files", FileColumns.DATA, values);
+ }
+
+ // Raw view shows everything.
+ assertThat(queryValues(helper, "audio", "title"))
+ .containsExactly(
+ "Clocks",
+ "My podcast title with false is_music",
+ "My podcast title with not set is_music");
+
+ // Artists and albums show only music files.
+ assertThat(queryValues(helper, "audio_artists", "artist"))
+ .containsExactly("Coldplay");
+ assertThat(queryValues(helper, "audio_albums", "album"))
+ .containsExactly("A Rush of Blood");
+
+ // Genres should show all genres.
+ assertThat(queryValues(helper, "audio_genres", "name"))
+ .containsExactly("Rock", "Podcast", "Podcast 2");
}
}
@@ -406,10 +471,6 @@
return sql != null ? sql.replace(", ", ",") : null;
}
- private static Set<String> asSet(String... vars) {
- return new ArraySet<>(Arrays.asList(vars));
- }
-
private static Set<String> queryValues(@NonNull DatabaseHelper helper, @NonNull String table,
@NonNull String columnName) {
try (Cursor c = helper.getWritableDatabaseForTest().query(table,
@@ -461,7 +522,8 @@
private static class DatabaseHelperR extends DatabaseHelper {
public DatabaseHelperR(Context context, String name) {
super(context, name, DatabaseHelper.VERSION_R,
- false, false, false, Column.class, null, null, null, null);
+ false, false, false, Column.class, null, null,
+ MediaProvider.MIGRATION_LISTENER, null);
}
}
diff --git a/tests/src/com/android/providers/media/MediaProviderTest.java b/tests/src/com/android/providers/media/MediaProviderTest.java
index 0749e02..83b722e 100644
--- a/tests/src/com/android/providers/media/MediaProviderTest.java
+++ b/tests/src/com/android/providers/media/MediaProviderTest.java
@@ -26,6 +26,7 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -47,11 +48,12 @@
import android.os.CancellationSignal;
import android.os.Environment;
import android.provider.MediaStore;
+import android.provider.MediaStore.Audio.AudioColumns;
+import android.provider.MediaStore.Files.FileColumns;
import android.provider.MediaStore.Images.ImageColumns;
import android.provider.MediaStore.MediaColumns;
import android.util.ArrayMap;
import android.util.Log;
-import android.util.Pair;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
@@ -1025,6 +1027,124 @@
}
}
+ @Test
+ public void testComputeAudioKeyValues_167339595_differentAlbumIds() throws Exception {
+ // same album name, different album artists
+ final ContentValues valuesOne = new ContentValues();
+ valuesOne.put(FileColumns.MEDIA_TYPE, FileColumns.MEDIA_TYPE_AUDIO);
+ valuesOne.put(FileColumns.VOLUME_NAME, MediaStore.VOLUME_EXTERNAL_PRIMARY);
+ valuesOne.put(FileColumns.DATA, "/storage/emulated/0/Clocks.mp3");
+ valuesOne.put(AudioColumns.TITLE, "Clocks");
+ valuesOne.put(AudioColumns.ALBUM, "A Rush of Blood");
+ valuesOne.put(AudioColumns.ALBUM_ARTIST, "Coldplay");
+ valuesOne.put(AudioColumns.GENRE, "Rock");
+ valuesOne.put(AudioColumns.IS_MUSIC, true);
+
+ final ContentValues valuesTwo = new ContentValues();
+ valuesTwo.put(FileColumns.MEDIA_TYPE, FileColumns.MEDIA_TYPE_AUDIO);
+ valuesTwo.put(FileColumns.VOLUME_NAME, MediaStore.VOLUME_EXTERNAL_PRIMARY);
+ valuesTwo.put(FileColumns.DATA, "/storage/emulated/0/Sounds.mp3");
+ valuesTwo.put(AudioColumns.TITLE, "Sounds");
+ valuesTwo.put(AudioColumns.ALBUM, "A Rush of Blood");
+ valuesTwo.put(AudioColumns.ALBUM_ARTIST, "ColdplayTwo");
+ valuesTwo.put(AudioColumns.GENRE, "Alternative rock");
+ valuesTwo.put(AudioColumns.IS_MUSIC, true);
+
+ MediaProvider.computeAudioKeyValues(valuesOne);
+ final long albumIdOne = valuesOne.getAsLong(AudioColumns.ALBUM_ID);
+ MediaProvider.computeAudioKeyValues(valuesTwo);
+ final long albumIdTwo = valuesTwo.getAsLong(AudioColumns.ALBUM_ID);
+
+ assertNotEquals(albumIdOne, albumIdTwo);
+
+ // same album name, different paths, no album artists
+ final ContentValues valuesThree = new ContentValues();
+ valuesThree.put(FileColumns.MEDIA_TYPE, FileColumns.MEDIA_TYPE_AUDIO);
+ valuesThree.put(FileColumns.VOLUME_NAME, MediaStore.VOLUME_EXTERNAL_PRIMARY);
+ valuesThree.put(FileColumns.DATA, "/storage/emulated/0/Silent.mp3");
+ valuesThree.put(AudioColumns.TITLE, "Silent");
+ valuesThree.put(AudioColumns.ALBUM, "Rainbow");
+ valuesThree.put(AudioColumns.ARTIST, "Sample1");
+ valuesThree.put(AudioColumns.GENRE, "Rock");
+ valuesThree.put(AudioColumns.IS_MUSIC, true);
+
+ final ContentValues valuesFour = new ContentValues();
+ valuesFour.put(FileColumns.MEDIA_TYPE, FileColumns.MEDIA_TYPE_AUDIO);
+ valuesFour.put(FileColumns.VOLUME_NAME, MediaStore.VOLUME_EXTERNAL_PRIMARY);
+ valuesFour.put(FileColumns.DATA, "/storage/emulated/0/123456/Rainbow.mp3");
+ valuesFour.put(AudioColumns.TITLE, "Rainbow");
+ valuesFour.put(AudioColumns.ALBUM, "Rainbow");
+ valuesFour.put(AudioColumns.ARTIST, "Sample2");
+ valuesFour.put(AudioColumns.GENRE, "Alternative rock");
+ valuesFour.put(AudioColumns.IS_MUSIC, true);
+
+ MediaProvider.computeAudioKeyValues(valuesThree);
+ final long albumIdThree = valuesThree.getAsLong(AudioColumns.ALBUM_ID);
+ MediaProvider.computeAudioKeyValues(valuesFour);
+ final long albumIdFour = valuesFour.getAsLong(AudioColumns.ALBUM_ID);
+
+ assertNotEquals(albumIdThree, albumIdFour);
+ }
+
+ @Test
+ public void testComputeAudioKeyValues_167339595_sameAlbumId() throws Exception {
+ // same album name, same path, no album artists
+ final ContentValues valuesOne = new ContentValues();
+ valuesOne.put(FileColumns.MEDIA_TYPE, FileColumns.MEDIA_TYPE_AUDIO);
+ valuesOne.put(FileColumns.VOLUME_NAME, MediaStore.VOLUME_EXTERNAL_PRIMARY);
+ valuesOne.put(FileColumns.DATA, "/storage/emulated/0/Clocks.mp3");
+ valuesOne.put(AudioColumns.TITLE, "Clocks");
+ valuesOne.put(AudioColumns.ALBUM, "A Rush of Blood");
+ valuesOne.put(AudioColumns.GENRE, "Rock");
+ valuesOne.put(AudioColumns.IS_MUSIC, true);
+
+ final ContentValues valuesTwo = new ContentValues();
+ valuesTwo.put(FileColumns.MEDIA_TYPE, FileColumns.MEDIA_TYPE_AUDIO);
+ valuesTwo.put(FileColumns.VOLUME_NAME, MediaStore.VOLUME_EXTERNAL_PRIMARY);
+ valuesTwo.put(FileColumns.DATA, "/storage/emulated/0/Sounds.mp3");
+ valuesTwo.put(AudioColumns.TITLE, "Sounds");
+ valuesTwo.put(AudioColumns.ALBUM, "A Rush of Blood");
+ valuesTwo.put(AudioColumns.GENRE, "Alternative rock");
+ valuesTwo.put(AudioColumns.IS_MUSIC, true);
+
+ MediaProvider.computeAudioKeyValues(valuesOne);
+ final long albumIdOne = valuesOne.getAsLong(AudioColumns.ALBUM_ID);
+ MediaProvider.computeAudioKeyValues(valuesTwo);
+ final long albumIdTwo = valuesTwo.getAsLong(AudioColumns.ALBUM_ID);
+
+ assertEquals(albumIdOne, albumIdTwo);
+
+ // same album name, same album artists, different artists
+ final ContentValues valuesThree = new ContentValues();
+ valuesThree.put(FileColumns.MEDIA_TYPE, FileColumns.MEDIA_TYPE_AUDIO);
+ valuesThree.put(FileColumns.VOLUME_NAME, MediaStore.VOLUME_EXTERNAL_PRIMARY);
+ valuesThree.put(FileColumns.DATA, "/storage/emulated/0/Silent.mp3");
+ valuesThree.put(AudioColumns.TITLE, "Silent");
+ valuesThree.put(AudioColumns.ALBUM, "Rainbow");
+ valuesThree.put(AudioColumns.ALBUM_ARTIST, "Various Artists");
+ valuesThree.put(AudioColumns.ARTIST, "Sample1");
+ valuesThree.put(AudioColumns.GENRE, "Rock");
+ valuesThree.put(AudioColumns.IS_MUSIC, true);
+
+ final ContentValues valuesFour = new ContentValues();
+ valuesFour.put(FileColumns.MEDIA_TYPE, FileColumns.MEDIA_TYPE_AUDIO);
+ valuesFour.put(FileColumns.VOLUME_NAME, MediaStore.VOLUME_EXTERNAL_PRIMARY);
+ valuesFour.put(FileColumns.DATA, "/storage/emulated/0/Rainbow.mp3");
+ valuesFour.put(AudioColumns.TITLE, "Rainbow");
+ valuesFour.put(AudioColumns.ALBUM, "Rainbow");
+ valuesFour.put(AudioColumns.ALBUM_ARTIST, "Various Artists");
+ valuesFour.put(AudioColumns.ARTIST, "Sample2");
+ valuesFour.put(AudioColumns.GENRE, "Alternative rock");
+ valuesFour.put(AudioColumns.IS_MUSIC, true);
+
+ MediaProvider.computeAudioKeyValues(valuesThree);
+ final long albumIdThree = valuesThree.getAsLong(AudioColumns.ALBUM_ID);
+ MediaProvider.computeAudioKeyValues(valuesFour);
+ final long albumIdFour = valuesFour.getAsLong(AudioColumns.ALBUM_ID);
+
+ assertEquals(albumIdThree, albumIdFour);
+ }
+
private static void assertRelativePathForDirectory(String directoryPath, String relativePath) {
assertWithMessage("extractRelativePathForDirectory(" + directoryPath + ") :")
.that(extractRelativePathWithDisplayName(directoryPath))
diff --git a/tests/src/com/android/providers/media/scan/ModernMediaScannerTest.java b/tests/src/com/android/providers/media/scan/ModernMediaScannerTest.java
index 59ef0f2..f7bb434 100644
--- a/tests/src/com/android/providers/media/scan/ModernMediaScannerTest.java
+++ b/tests/src/com/android/providers/media/scan/ModernMediaScannerTest.java
@@ -45,18 +45,22 @@
import static org.mockito.Mockito.when;
import android.Manifest;
+import android.app.UiAutomation;
import android.content.ContentResolver;
import android.content.ContentUris;
+import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.media.ExifInterface;
import android.media.MediaMetadataRetriever;
import android.net.Uri;
+import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.provider.MediaStore;
import android.provider.MediaStore.Files.FileColumns;
import android.provider.MediaStore.MediaColumns;
+import android.util.Log;
import android.util.Pair;
import androidx.test.InstrumentationRegistry;
@@ -66,19 +70,26 @@
import com.android.providers.media.scan.MediaScannerTest.IsolatedContext;
import com.android.providers.media.util.FileUtils;
+import com.google.common.io.ByteStreams;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InterruptedIOException;
import java.util.Optional;
@RunWith(AndroidJUnit4.class)
public class ModernMediaScannerTest {
// TODO: scan directory-vs-files and confirm identical results
+ private static final String TAG = "ModernMediaScannerTest";
private File mDir;
private Context mIsolatedContext;
@@ -399,6 +410,41 @@
}
}
+ private void assertVisibleFolder(File dir) throws Exception {
+ final File nomediaFile = new File(dir, ".nomedia");
+
+ if (!nomediaFile.getParentFile().exists()) {
+ assertTrue(nomediaFile.getParentFile().mkdirs());
+ }
+ try {
+ if (!nomediaFile.exists()) {
+ executeShellCommand("touch " + nomediaFile.getAbsolutePath());
+ assertTrue(nomediaFile.exists());
+ }
+ assertShouldScanPathAndIsPathHidden(true, false, dir);
+ } finally {
+ executeShellCommand("rm " + nomediaFile.getAbsolutePath());
+ }
+ }
+
+ /**
+ * b/168830497: Test that default folders and Camera folder are always visible
+ */
+ @Test
+ public void testVisibleDefaultFolders() throws Exception {
+ final File root = new File("storage/emulated/0");
+
+ // Top level directories should always be visible
+ for (String dirName : FileUtils.DEFAULT_FOLDER_NAMES) {
+ final File defaultFolder = new File(root, dirName);
+ assertVisibleFolder(defaultFolder);
+ }
+
+ // DCIM/Camera should always be visible
+ final File cameraDir = new File(root, Environment.DIRECTORY_DCIM + "/" + "Camera");
+ assertVisibleFolder(cameraDir);
+ }
+
private static void assertShouldScanDirectory(File file) {
assertTrue(file.getAbsolutePath(), shouldScanDirectory(file));
}
@@ -820,6 +866,31 @@
}
}
+ /**
+ * If there is a scan action between invoking {@link ContentResolver#insert} and
+ * {@link ContentResolver#openFileDescriptor}, it should not raise
+ * (@link FileNotFoundException}.
+ */
+ @Test
+ public void testScan_166063754() throws Exception {
+ Uri collection = MediaStore.Images.Media
+ .getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
+
+ ContentValues values = new ContentValues();
+ values.put(MediaStore.Images.Media.DISPLAY_NAME, mDir.getName() + "_166063754.jpg");
+ values.put(MediaStore.Images.Media.IS_PENDING, 1);
+
+ Uri uri = mIsolatedResolver.insert(collection, values);
+
+ File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
+ mModern.scanFile(dir, REASON_UNKNOWN);
+ try {
+ mIsolatedResolver.openFileDescriptor(uri, "w", null);
+ } catch (FileNotFoundException e) {
+ throw new AssertionError("Can't open uri " + uri, e);
+ }
+ }
+
@Test
public void testAlbumArtPattern() throws Exception {
for (String path : new String[] {
@@ -853,4 +924,29 @@
assertTrue(isFileAlbumArt(file));
}
}
+
+ /**
+ * Executes a shell command.
+ */
+ public static String executeShellCommand(String command) throws IOException {
+ int attempt = 0;
+ while (attempt++ < 5) {
+ try {
+ return executeShellCommandInternal(command);
+ } catch (InterruptedIOException e) {
+ // Hmm, we had trouble executing the shell command; the best we
+ // can do is try again a few more times
+ Log.v(TAG, "Trouble executing " + command + "; trying again", e);
+ }
+ }
+ throw new IOException("Failed to execute " + command);
+ }
+
+ private static String executeShellCommandInternal(String cmd) throws IOException {
+ UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ try (FileInputStream output = new FileInputStream(
+ uiAutomation.executeShellCommand(cmd).getFileDescriptor())) {
+ return new String(ByteStreams.toByteArray(output));
+ }
+ }
}
diff --git a/tests/src/com/android/providers/media/util/SQLiteQueryBuilderTest.java b/tests/src/com/android/providers/media/util/SQLiteQueryBuilderTest.java
index 9af8e5d..c8fe3bb 100644
--- a/tests/src/com/android/providers/media/util/SQLiteQueryBuilderTest.java
+++ b/tests/src/com/android/providers/media/util/SQLiteQueryBuilderTest.java
@@ -741,6 +741,25 @@
}
@Test
+ public void testStrict_158537159() {
+ final SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
+ final HashMap<String, String> map = new HashMap<>();
+ map.put("bucket_id", "bucket_id");
+ builder.setProjectionMap(map);
+ final String sortOrder = "bucket_id COLLATE LOCALIZED ASC";
+ {
+ builder.setTargetSdkVersion(Build.VERSION_CODES.Q);
+ builder.enforceStrictGrammar(null, null, null, sortOrder, null);
+ }
+ try {
+ builder.setTargetSdkVersion(Build.VERSION_CODES.R);
+ builder.enforceStrictGrammar(null, null, null, sortOrder, null);
+ fail("Expected to throw");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ @Test
public void testStrictCustomCollator() {
final SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
final HashMap<String, String> map = new HashMap<>();