Merge "Add api tracking files for MediaProvider" into rvc-dev
diff --git a/gen_strings.py b/gen_strings.py
old mode 100644
new mode 100755
index ee06841..99bba8a
--- a/gen_strings.py
+++ b/gen_strings.py
@@ -29,7 +29,7 @@
 for verb in verbs:
     verblabel = verb
     if verb == "write":
-        verblabel = "change"
+        verblabel = "modify"
 
     verblabelcaps = verblabel[0].upper() + verblabel[1:]
     if verb == "trash":
@@ -45,15 +45,8 @@
             print Template('''
 <!-- Dialog title asking if user will allow $verb permission to the $data item displayed below this string. [CHAR LIMIT=128] -->
 <plurals name="permission_${verb}_${data}">
-    <item quantity="one">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> move this $datalabel to trash?</item>
-    <item quantity="other">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> move <xliff:g id="count" example="42">^2</xliff:g> ${datalabel}s to trash?</item>
-</plurals>
-''').substitute(vars()).strip("\n")
-            print Template('''
-<!-- Dialog body text explaining that this $data item will be permanently deleted after the shown duration. [CHAR LIMIT=128] -->
-<plurals name="permission_${verb}_${data}_info">
-    <item quantity="one">This $datalabel will be permanently deleted after <xliff:g id="duration" example="42">^3</xliff:g> days</item>
-    <item quantity="other">These ${datalabel}s will be permanently deleted after <xliff:g id="duration" example="42">^3</xliff:g> days</item>
+    <item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move this $datalabel to trash?</item>
+    <item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move <xliff:g id="count" example="42">^2</xliff:g> ${datalabel}s to trash?</item>
 </plurals>
 ''').substitute(vars()).strip("\n")
 
@@ -61,8 +54,8 @@
             print Template('''
 <!-- Dialog title asking if user will allow $verb permission to the $data item displayed below this string. [CHAR LIMIT=128] -->
 <plurals name="permission_${verb}_${data}">
-    <item quantity="one">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> move this $datalabel out of trash?</item>
-    <item quantity="other">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> move <xliff:g id="count" example="42">^2</xliff:g> ${datalabel}s out of trash?</item>
+    <item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move this $datalabel out of trash?</item>
+    <item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move <xliff:g id="count" example="42">^2</xliff:g> ${datalabel}s out of trash?</item>
 </plurals>
 ''').substitute(vars()).strip("\n")
 
@@ -70,19 +63,11 @@
             print Template('''
 <!-- Dialog title asking if user will allow $verb permission to the $data item displayed below this string. [CHAR LIMIT=128] -->
 <plurals name="permission_${verb}_${data}">
-    <item quantity="one">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> $verblabel this $datalabel?</item>
-    <item quantity="other">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> $verblabel <xliff:g id="count" example="42">^2</xliff:g> ${datalabel}s?</item>
+    <item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to $verblabel this $datalabel?</item>
+    <item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to $verblabel <xliff:g id="count" example="42">^2</xliff:g> ${datalabel}s?</item>
 </plurals>
 ''').substitute(vars()).strip("\n")
 
-
-    print Template('''
-<!-- Positive dialog button confirming that $verb permission should be granted. [CHAR LIMIT=32] -->
-<string name="permission_${verb}_grant">${verblabelcaps}</string>
-<!-- Negative dialog button confirming that $verb permission should not be granted. [CHAR LIMIT=32] -->
-<string name="permission_${verb}_deny">Cancel</string>
-''').substitute(vars()).strip("\n")
-
 print '''
 <!-- ========================= END AUTO-GENERATED BY gen_strings.py ========================= -->
 '''
diff --git a/jni/FuseDaemon.cpp b/jni/FuseDaemon.cpp
index a014489..d014a8e 100644
--- a/jni/FuseDaemon.cpp
+++ b/jni/FuseDaemon.cpp
@@ -816,7 +816,7 @@
     // FUSE after that write may be served from cache
     bool direct_io = ri->isRedactionNeeded() || is_file_locked(fd, path);
 
-    handle* h = new handle(path, fd, ri, /*owner_uid*/ -1, !direct_io);
+    handle* h = new handle(path, fd, ri, !direct_io);
     node->AddHandle(h);
     return h;
 }
@@ -1080,11 +1080,6 @@
 
     fuse->fadviser.Close(h->fd);
     if (node) {
-        // TODO(b/145737191) Legacy apps don't expect FuseDaemon to update database.
-        // Inserting/deleting the database entry might break app's functionality.
-        // if (h->owner_uid != -1) {
-        //    fuse->mp->ScanFile(h->path, h->owner_uid);
-        // }
         node->DestroyHandle(h);
     }
 
diff --git a/jni/MediaProviderWrapper.cpp b/jni/MediaProviderWrapper.cpp
index 0cdfd87..77e1470 100644
--- a/jni/MediaProviderWrapper.cpp
+++ b/jni/MediaProviderWrapper.cpp
@@ -116,9 +116,9 @@
 }
 
 void scanFileInternal(JNIEnv* env, jobject media_provider_object, jmethodID mid_scan_file,
-                      const string& path, uid_t uid) {
+                      const string& path) {
     ScopedLocalRef<jstring> j_path(env, env->NewStringUTF(path.c_str()));
-    env->CallVoidMethod(media_provider_object, mid_scan_file, j_path.get(), uid);
+    env->CallVoidMethod(media_provider_object, mid_scan_file, j_path.get());
     CheckForJniException(env);
 }
 
@@ -241,7 +241,7 @@
     mid_delete_file_ = CacheMethod(env, "deleteFile", "(Ljava/lang/String;I)I", /*is_static*/ false);
     mid_is_open_allowed_ = CacheMethod(env, "isOpenAllowed", "(Ljava/lang/String;IZ)I",
                                        /*is_static*/ false);
-    mid_scan_file_ = CacheMethod(env, "scanFile", "(Ljava/lang/String;I)V",
+    mid_scan_file_ = CacheMethod(env, "scanFile", "(Ljava/lang/String;)V",
                                  /*is_static*/ false);
     mid_is_mkdir_or_rmdir_allowed_ = CacheMethod(env, "isDirectoryCreationOrDeletionAllowed",
                                                  "(Ljava/lang/String;IZ)I", /*is_static*/ false);
@@ -290,7 +290,7 @@
 int MediaProviderWrapper::DeleteFile(const string& path, uid_t uid) {
     if (shouldBypassMediaProvider(uid)) {
         int res = unlink(path.c_str());
-        ScanFile(path, uid);
+        ScanFile(path);
         return res;
     }
 
@@ -308,15 +308,9 @@
                                  for_write);
 }
 
-void MediaProviderWrapper::ScanFile(const string& path, uid_t uid) {
-    if (uid == 0) {
-        // uid = 0 is kernel or adb shell running as root and doesn't have a package associated with
-        // it. This uid should get global access hence use MediaProvider's uid.
-        uid = getuid();
-    }
-
+void MediaProviderWrapper::ScanFile(const string& path) {
     JNIEnv* env = MaybeAttachCurrentThread();
-    scanFileInternal(env, media_provider_object_, mid_scan_file_, path, uid);
+    scanFileInternal(env, media_provider_object_, mid_scan_file_, path);
 }
 
 int MediaProviderWrapper::IsCreatingDirAllowed(const string& path, uid_t uid) {
diff --git a/jni/MediaProviderWrapper.h b/jni/MediaProviderWrapper.h
index 22c5b3e..016696f 100644
--- a/jni/MediaProviderWrapper.h
+++ b/jni/MediaProviderWrapper.h
@@ -105,9 +105,8 @@
      * MediaProvider database.
      *
      * @param path the path of the file to be scanned
-     * @param uid UID of the app that owns the file on the given path
      */
-    void ScanFile(const std::string& path, uid_t uid);
+    void ScanFile(const std::string& path);
 
     /**
      * Determines if the given UID is allowed to create a directory with the given path.
diff --git a/jni/node-inl.h b/jni/node-inl.h
index 5098316..a146d20 100644
--- a/jni/node-inl.h
+++ b/jni/node-inl.h
@@ -36,16 +36,14 @@
 namespace fuse {
 
 struct handle {
-    explicit handle(const std::string& path, int fd, const RedactionInfo* ri, uid_t owner_uid,
-                    bool cached)
-        : path(path), fd(fd), ri(ri), owner_uid(owner_uid), cached(cached) {
+    explicit handle(const std::string& path, int fd, const RedactionInfo* ri, bool cached)
+        : path(path), fd(fd), ri(ri), cached(cached) {
         CHECK(ri != nullptr);
     }
 
     const std::string path;
     const int fd;
     const std::unique_ptr<const RedactionInfo> ri;
-    const uid_t owner_uid;
     const bool cached;
 
     ~handle() { close(fd); }
diff --git a/jni/node_test.cpp b/jni/node_test.cpp
index 423af3d..fd56f49 100644
--- a/jni/node_test.cpp
+++ b/jni/node_test.cpp
@@ -213,8 +213,7 @@
 TEST_F(NodeTest, AddDestroyHandle) {
     unique_node_ptr node = CreateNode(nullptr, "/path");
 
-    handle* h = new handle("/path", -1, new mediaprovider::fuse::RedactionInfo, getuid(),
-                           true /* cached */);
+    handle* h = new handle("/path", -1, new mediaprovider::fuse::RedactionInfo, true /* cached */);
     node->AddHandle(h);
     ASSERT_TRUE(node->HasCachedHandle());
 
@@ -225,7 +224,7 @@
     // the node in question.
     EXPECT_DEATH(node->DestroyHandle(h), "");
     EXPECT_DEATH(node->DestroyHandle(nullptr), "");
-    std::unique_ptr<handle> h2(new handle("/path2", -1, new mediaprovider::fuse::RedactionInfo,
-                                          getuid(), true /* cached */));
+    std::unique_ptr<handle> h2(
+            new handle("/path2", -1, new mediaprovider::fuse::RedactionInfo, true /* cached */));
     EXPECT_DEATH(node->DestroyHandle(h2.get()), "");
 }
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 04cab66..ef51112 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -51,6 +51,7 @@
 
     <!-- Text placed over a visual thumbnail indicating that there are more items beyond the number currently displayed on the screen. [CHAR LIMIT=6] -->
     <plurals name="permission_more_thumb">
+        <item quantity="one">+<xliff:g id="count" example="1">^1</xliff:g></item>
         <item quantity="other">+<xliff:g id="count" example="42">^1</xliff:g></item>
     </plurals>
 
@@ -61,10 +62,10 @@
     </plurals>
 
     <!-- Cache clearing permission dialog warning title. [CHAR LIMIT=NONE] -->
-    <string name="cache_clearing_dialog_title">Clear app cache with <xliff:g id="app_seeking_permission" example="File manager">%s</xliff:g>?</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. Accepting may increase battery or data use.</string>
+    <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>
 
     <!-- Allow dialog action text. [CHAR LIMIT=30] -->
     <string name="allow">Allow</string>
@@ -78,129 +79,93 @@
 
     <!-- Dialog title asking if user will allow write permission to the audio item displayed below this string. [CHAR LIMIT=128] -->
     <plurals name="permission_write_audio">
-        <item quantity="one">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> change this audio file?</item>
-        <item quantity="other">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> change <xliff:g id="count" example="42">^2</xliff:g> audio files?</item>
+        <item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to modify this audio file?</item>
+        <item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to modify <xliff:g id="count" example="42">^2</xliff:g> audio files?</item>
     </plurals>
     <!-- Dialog title asking if user will allow write permission to the video item displayed below this string. [CHAR LIMIT=128] -->
     <plurals name="permission_write_video">
-        <item quantity="one">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> change this video?</item>
-        <item quantity="other">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> change <xliff:g id="count" example="42">^2</xliff:g> videos?</item>
+        <item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to modify this video?</item>
+        <item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to modify <xliff:g id="count" example="42">^2</xliff:g> videos?</item>
     </plurals>
     <!-- Dialog title asking if user will allow write permission to the image item displayed below this string. [CHAR LIMIT=128] -->
     <plurals name="permission_write_image">
-        <item quantity="one">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> change this photo?</item>
-        <item quantity="other">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> change <xliff:g id="count" example="42">^2</xliff:g> photos?</item>
+        <item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to modify this photo?</item>
+        <item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to modify <xliff:g id="count" example="42">^2</xliff:g> photos?</item>
     </plurals>
     <!-- Dialog title asking if user will allow write permission to the generic item displayed below this string. [CHAR LIMIT=128] -->
     <plurals name="permission_write_generic">
-        <item quantity="one">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> change this item?</item>
-        <item quantity="other">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> change <xliff:g id="count" example="42">^2</xliff:g> items?</item>
+        <item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to modify this item?</item>
+        <item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to modify <xliff:g id="count" example="42">^2</xliff:g> items?</item>
     </plurals>
-    <!-- Positive dialog button confirming that write permission should be granted. [CHAR LIMIT=32] -->
-    <string name="permission_write_grant">Change</string>
-    <!-- Negative dialog button confirming that write permission should not be granted. [CHAR LIMIT=32] -->
-    <string name="permission_write_deny">Cancel</string>
 
     <!-- ========================= TRASH STRINGS ========================= -->
 
     <!-- Dialog title asking if user will allow trash permission to the audio item displayed below this string. [CHAR LIMIT=128] -->
     <plurals name="permission_trash_audio">
-        <item quantity="one">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> move this audio file to trash?</item>
-        <item quantity="other">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> move <xliff:g id="count" example="42">^2</xliff:g> audio files to trash?</item>
-    </plurals>
-    <!-- Dialog body text explaining that this audio item will be permanently deleted after the shown duration. [CHAR LIMIT=128] -->
-    <plurals name="permission_trash_audio_info">
-        <item quantity="one">This audio file will be permanently deleted after <xliff:g id="duration" example="42">^3</xliff:g> days</item>
-        <item quantity="other">These audio files will be permanently deleted after <xliff:g id="duration" example="42">^3</xliff:g> days</item>
+        <item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move this audio file to trash?</item>
+        <item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move <xliff:g id="count" example="42">^2</xliff:g> audio files to trash?</item>
     </plurals>
     <!-- Dialog title asking if user will allow trash permission to the video item displayed below this string. [CHAR LIMIT=128] -->
     <plurals name="permission_trash_video">
-        <item quantity="one">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> move this video to trash?</item>
-        <item quantity="other">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> move <xliff:g id="count" example="42">^2</xliff:g> videos to trash?</item>
-    </plurals>
-    <!-- Dialog body text explaining that this video item will be permanently deleted after the shown duration. [CHAR LIMIT=128] -->
-    <plurals name="permission_trash_video_info">
-        <item quantity="one">This video will be permanently deleted after <xliff:g id="duration" example="42">^3</xliff:g> days</item>
-        <item quantity="other">These videos will be permanently deleted after <xliff:g id="duration" example="42">^3</xliff:g> days</item>
+        <item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move this video to trash?</item>
+        <item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move <xliff:g id="count" example="42">^2</xliff:g> videos to trash?</item>
     </plurals>
     <!-- Dialog title asking if user will allow trash permission to the image item displayed below this string. [CHAR LIMIT=128] -->
     <plurals name="permission_trash_image">
-        <item quantity="one">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> move this photo to trash?</item>
-        <item quantity="other">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> move <xliff:g id="count" example="42">^2</xliff:g> photos to trash?</item>
-    </plurals>
-    <!-- Dialog body text explaining that this image item will be permanently deleted after the shown duration. [CHAR LIMIT=128] -->
-    <plurals name="permission_trash_image_info">
-        <item quantity="one">This photo will be permanently deleted after <xliff:g id="duration" example="42">^3</xliff:g> days</item>
-        <item quantity="other">These photos will be permanently deleted after <xliff:g id="duration" example="42">^3</xliff:g> days</item>
+        <item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move this photo to trash?</item>
+        <item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move <xliff:g id="count" example="42">^2</xliff:g> photos to trash?</item>
     </plurals>
     <!-- Dialog title asking if user will allow trash permission to the generic item displayed below this string. [CHAR LIMIT=128] -->
     <plurals name="permission_trash_generic">
-        <item quantity="one">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> move this item to trash?</item>
-        <item quantity="other">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> move <xliff:g id="count" example="42">^2</xliff:g> items to trash?</item>
+        <item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move this item to trash?</item>
+        <item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move <xliff:g id="count" example="42">^2</xliff:g> items to trash?</item>
     </plurals>
-    <!-- Dialog body text explaining that this generic item will be permanently deleted after the shown duration. [CHAR LIMIT=128] -->
-    <plurals name="permission_trash_generic_info">
-        <item quantity="one">This item will be permanently deleted after <xliff:g id="duration" example="42">^3</xliff:g> days</item>
-        <item quantity="other">These items will be permanently deleted after <xliff:g id="duration" example="42">^3</xliff:g> days</item>
-    </plurals>
-    <!-- Positive dialog button confirming that trash permission should be granted. [CHAR LIMIT=32] -->
-    <string name="permission_trash_grant">Move to trash</string>
-    <!-- Negative dialog button confirming that trash permission should not be granted. [CHAR LIMIT=32] -->
-    <string name="permission_trash_deny">Cancel</string>
 
     <!-- ========================= UNTRASH STRINGS ========================= -->
 
     <!-- Dialog title asking if user will allow untrash permission to the audio item displayed below this string. [CHAR LIMIT=128] -->
     <plurals name="permission_untrash_audio">
-        <item quantity="one">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> move this audio file out of trash?</item>
-        <item quantity="other">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> move <xliff:g id="count" example="42">^2</xliff:g> audio files out of trash?</item>
+        <item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move this audio file out of trash?</item>
+        <item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move <xliff:g id="count" example="42">^2</xliff:g> audio files out of trash?</item>
     </plurals>
     <!-- Dialog title asking if user will allow untrash permission to the video item displayed below this string. [CHAR LIMIT=128] -->
     <plurals name="permission_untrash_video">
-        <item quantity="one">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> move this video out of trash?</item>
-        <item quantity="other">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> move <xliff:g id="count" example="42">^2</xliff:g> videos out of trash?</item>
+        <item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move this video out of trash?</item>
+        <item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move <xliff:g id="count" example="42">^2</xliff:g> videos out of trash?</item>
     </plurals>
     <!-- Dialog title asking if user will allow untrash permission to the image item displayed below this string. [CHAR LIMIT=128] -->
     <plurals name="permission_untrash_image">
-        <item quantity="one">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> move this photo out of trash?</item>
-        <item quantity="other">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> move <xliff:g id="count" example="42">^2</xliff:g> photos out of trash?</item>
+        <item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move this photo out of trash?</item>
+        <item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move <xliff:g id="count" example="42">^2</xliff:g> photos out of trash?</item>
     </plurals>
     <!-- Dialog title asking if user will allow untrash permission to the generic item displayed below this string. [CHAR LIMIT=128] -->
     <plurals name="permission_untrash_generic">
-        <item quantity="one">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> move this item out of trash?</item>
-        <item quantity="other">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> move <xliff:g id="count" example="42">^2</xliff:g> items out of trash?</item>
+        <item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move this item out of trash?</item>
+        <item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to move <xliff:g id="count" example="42">^2</xliff:g> items out of trash?</item>
     </plurals>
-    <!-- Positive dialog button confirming that untrash permission should be granted. [CHAR LIMIT=32] -->
-    <string name="permission_untrash_grant">Move out of trash</string>
-    <!-- Negative dialog button confirming that untrash permission should not be granted. [CHAR LIMIT=32] -->
-    <string name="permission_untrash_deny">Cancel</string>
 
     <!-- ========================= DELETE STRINGS ========================= -->
 
     <!-- Dialog title asking if user will allow delete permission to the audio item displayed below this string. [CHAR LIMIT=128] -->
     <plurals name="permission_delete_audio">
-        <item quantity="one">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> delete this audio file?</item>
-        <item quantity="other">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> delete <xliff:g id="count" example="42">^2</xliff:g> audio files?</item>
+        <item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to delete this audio file?</item>
+        <item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to delete <xliff:g id="count" example="42">^2</xliff:g> audio files?</item>
     </plurals>
     <!-- Dialog title asking if user will allow delete permission to the video item displayed below this string. [CHAR LIMIT=128] -->
     <plurals name="permission_delete_video">
-        <item quantity="one">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> delete this video?</item>
-        <item quantity="other">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> delete <xliff:g id="count" example="42">^2</xliff:g> videos?</item>
+        <item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to delete this video?</item>
+        <item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to delete <xliff:g id="count" example="42">^2</xliff:g> videos?</item>
     </plurals>
     <!-- Dialog title asking if user will allow delete permission to the image item displayed below this string. [CHAR LIMIT=128] -->
     <plurals name="permission_delete_image">
-        <item quantity="one">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> delete this photo?</item>
-        <item quantity="other">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> delete <xliff:g id="count" example="42">^2</xliff:g> photos?</item>
+        <item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to delete this photo?</item>
+        <item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to delete <xliff:g id="count" example="42">^2</xliff:g> photos?</item>
     </plurals>
     <!-- Dialog title asking if user will allow delete permission to the generic item displayed below this string. [CHAR LIMIT=128] -->
     <plurals name="permission_delete_generic">
-        <item quantity="one">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> delete this item?</item>
-        <item quantity="other">Let <xliff:g id="app_name" example="Gmail">^1</xliff:g> delete <xliff:g id="count" example="42">^2</xliff:g> items?</item>
+        <item quantity="one">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to delete this item?</item>
+        <item quantity="other">Allow <xliff:g id="app_name" example="Gmail">^1</xliff:g> to delete <xliff:g id="count" example="42">^2</xliff:g> items?</item>
     </plurals>
-    <!-- Positive dialog button confirming that delete permission should be granted. [CHAR LIMIT=32] -->
-    <string name="permission_delete_grant">Delete</string>
-    <!-- Negative dialog button confirming that delete permission should not be granted. [CHAR LIMIT=32] -->
-    <string name="permission_delete_deny">Cancel</string>
 
     <!-- ========================= END AUTO-GENERATED BY gen_strings.py ========================= -->
 
diff --git a/src/com/android/providers/media/LocalCallingIdentity.java b/src/com/android/providers/media/LocalCallingIdentity.java
index ef6c27f..f767dcd 100644
--- a/src/com/android/providers/media/LocalCallingIdentity.java
+++ b/src/com/android/providers/media/LocalCallingIdentity.java
@@ -37,8 +37,6 @@
 import android.annotation.Nullable;
 import android.app.AppOpsManager;
 import android.app.compat.CompatChanges;
-import android.compat.annotation.ChangeId;
-import android.compat.annotation.Disabled;
 import android.content.ContentProvider;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -69,39 +67,13 @@
     }
 
     /**
-     * Scoped Storage is on by default. However, it is not strictly enforced and there are multiple
-     * ways to opt out of scoped storage:
-     * <ul>
-     * <li>Target Sdk < Q</li>
-     * <li>Target Sdk = Q and has `requestLegacyExternalStorage` set in AndroidManifest.xml</li>
-     * <li>Target Sdk > Q: Upgrading from an app that was opted out of scoped storage and has
-     * `preserveLegacyExternalStorage` set in AndroidManifest.xml</li>
-     * </ul>
-     * This flag is enabled for all apps by default as Scoped Storage is enabled by default.
-     * Developers can disable this flag to opt out of Scoped Storage and have legacy storage
-     * workflow.
-     *
-     * Note: {@code FORCE_ENABLE_SCOPED_STORAGE} should also be disabled for apps to opt out of
-     * scoped storage.
-     * See https://developer.android.com/training/data-storage#scoped-storage for more information.
+     * See definition in {@link android.os.Environment}
      */
-    @ChangeId
     private static final long DEFAULT_SCOPED_STORAGE = 149924527L;
 
     /**
-     * Setting this flag strictly enforces Scoped Storage regardless of:
-     * <ul>
-     * <li>The value of Target Sdk</li>
-     * <li>The value of `requestLegacyExternalStorage` in AndroidManifest.xml</li>
-     * <li>The value of `preserveLegacyExternalStorage` in AndroidManifest.xml</li>
-     * </ul>
-     *
-     * Note: {@code DEFAULT_SCOPED_STORAGE} should also be enabled for apps to be enforced into
-     * scoped storage.
-     * See https://developer.android.com/training/data-storage#scoped-storage for more information.
+     * See definition in {@link android.os.Environment}
      */
-    @ChangeId
-    @Disabled
     private static final long FORCE_ENABLE_SCOPED_STORAGE = 132649864L;
 
     public static LocalCallingIdentity fromBinder(Context context, ContentProvider provider) {
diff --git a/src/com/android/providers/media/MediaProvider.java b/src/com/android/providers/media/MediaProvider.java
index 67b7d86..7507c0b 100644
--- a/src/com/android/providers/media/MediaProvider.java
+++ b/src/com/android/providers/media/MediaProvider.java
@@ -64,7 +64,10 @@
 import static com.android.providers.media.util.FileUtils.extractRelativePathForDirectory;
 import static com.android.providers.media.util.FileUtils.extractTopLevelDir;
 import static com.android.providers.media.util.FileUtils.extractVolumeName;
+import static com.android.providers.media.util.FileUtils.getAbsoluteSanitizedPath;
 import static com.android.providers.media.util.FileUtils.isDownload;
+import static com.android.providers.media.util.FileUtils.sanitizeDisplayName;
+import static com.android.providers.media.util.FileUtils.sanitizePath;
 import static com.android.providers.media.util.Logging.LOGV;
 import static com.android.providers.media.util.Logging.TAG;
 import static com.android.providers.media.util.PermissionUtils.checkPermissionManageExternalStorage;
@@ -256,6 +259,8 @@
     private static final String INCLUDED_DEFAULT_DIRECTORIES =
             "android:included-default-directories";
 
+    private static final int UNKNOWN_UID = -1;
+
     /**
      * Set of {@link Cursor} columns that refer to raw filesystem paths.
      */
@@ -343,8 +348,8 @@
 
     /**
      * Map from UID to cached {@link LocalCallingIdentity}. Values are only
-     * maintained in this map while the UID is actively working with a
-     * performance-critical component, such as camera.
+     * maintained in this map until there's any change in the appops needed or packages
+     * used in the {@link LocalCallingIdentity}.
      */
     @GuardedBy("mCachedCallingIdentity")
     private final SparseArray<LocalCallingIdentity> mCachedCallingIdentity = new SparseArray<>();
@@ -362,24 +367,28 @@
         }
     };
 
-    /**
-     * Map from UID to cached {@link LocalCallingIdentity}. Values are only
-     * maintained in this map until there's any change in the appops needed or packages
-     * used in the {@link LocalCallingIdentity}.
-     */
-    @GuardedBy("mCachedCallingIdentityForFuse")
-    private final SparseArray<LocalCallingIdentity> mCachedCallingIdentityForFuse =
-            new SparseArray<>();
-
     private OnOpChangedListener mModeListener =
-            (op, packageName) -> invalidateLocalCallingIdentityCache(packageName, "op " + op);
+            (op, packageName) -> invalidateLocalCallingIdentityCache(UNKNOWN_UID, packageName,
+                    "op " + op);
 
     private LocalCallingIdentity getCachedCallingIdentityForFuse(int uid) {
-        synchronized (mCachedCallingIdentityForFuse) {
-            LocalCallingIdentity ident = mCachedCallingIdentityForFuse.get(uid);
+        synchronized (mCachedCallingIdentity) {
+            LocalCallingIdentity ident = mCachedCallingIdentity.get(uid);
             if (ident == null) {
-               ident = LocalCallingIdentity.fromExternal(getContext(), uid);
-               mCachedCallingIdentityForFuse.put(uid, ident);
+                ident = LocalCallingIdentity.fromExternal(getContext(), uid);
+                mCachedCallingIdentity.put(uid, ident);
+            }
+            return ident;
+        }
+    }
+
+    private LocalCallingIdentity getCachedCallingIdentityForBinder() {
+        int uid = Binder.getCallingUid();
+        synchronized (mCachedCallingIdentity) {
+            LocalCallingIdentity ident = mCachedCallingIdentity.get(uid);
+            if (ident == null) {
+                ident = LocalCallingIdentity.fromBinder(getContext(), this);
+                mCachedCallingIdentity.put(uid, ident);
             }
             return ident;
         }
@@ -391,14 +400,7 @@
      * call is finished.
      */
     private final ThreadLocal<LocalCallingIdentity> mCallingIdentity = ThreadLocal
-            .withInitial(() -> {
-                synchronized (mCachedCallingIdentity) {
-                    final LocalCallingIdentity cached = mCachedCallingIdentity
-                            .get(Binder.getCallingUid());
-                    return (cached != null) ? cached
-                            : LocalCallingIdentity.fromBinder(getContext(), this);
-                }
-            });
+            .withInitial(this::getCachedCallingIdentityForBinder);
 
     /**
      * We simply propagate the UID that is being tracked by
@@ -480,7 +482,9 @@
                     Uri uri = intent.getData();
                     String pkg = uri != null ? uri.getSchemeSpecificPart() : null;
                     if (pkg != null) {
-                        invalidateLocalCallingIdentityCache(pkg, "package " + intent.getAction());
+                        int uid = intent.getIntExtra(Intent.EXTRA_UID, UNKNOWN_UID);
+                        invalidateLocalCallingIdentityCache(uid, pkg,
+                                "package " + intent.getAction());
                     } else {
                         Log.w(TAG, "Failed to retrieve package from intent: " + intent.getAction());
                     }
@@ -489,15 +493,21 @@
         }
     };
 
-    private void invalidateLocalCallingIdentityCache(String packageName, String reason) {
-        synchronized (mCachedCallingIdentityForFuse) {
-            try {
-                Log.i(TAG, "Invalidating LocalCallingIdentity cache for package " + packageName
-                        + ". Reason: " + reason);
-                mCachedCallingIdentityForFuse.remove(
-                        getContext().getPackageManager().getPackageUid(packageName, 0));
-            } catch (NameNotFoundException ignored) {
+    private void invalidateLocalCallingIdentityCache(int uid, String packageName, String reason) {
+        try {
+            if (uid == UNKNOWN_UID) {
+                uid = getContext().getPackageManager().getPackageUid(packageName, 0);
             }
+        } catch (NameNotFoundException e) {
+            Log.wtf(TAG, "Failed to invalidate LocalCallingIdentity cache for package: "
+                    + packageName, e);
+            return;
+        }
+
+        synchronized (mCachedCallingIdentity) {
+            Log.i(TAG, "Invalidating LocalCallingIdentity cache for package " + packageName
+                    + ". Uid: " + uid + ". Reason: " + reason);
+            mCachedCallingIdentity.remove(uid);
         }
     }
 
@@ -816,7 +826,6 @@
                 AppOpsManager.OPSTR_CAMERA
         }, context.getMainExecutor(), mActiveListener);
 
-
         mAppOpsManager.startWatchingMode(AppOpsManager.OPSTR_READ_EXTERNAL_STORAGE,
                 null /* all packages */, mModeListener);
         mAppOpsManager.startWatchingMode(AppOpsManager.OPSTR_WRITE_EXTERNAL_STORAGE,
@@ -962,6 +971,11 @@
             mDirectoryCache.clear();
         }
 
+        // Purge any per uid caches
+        synchronized (mCachedCallingIdentity) {
+            mCachedCallingIdentity.clear();
+        }
+
         final long durationMillis = (SystemClock.elapsedRealtime() - startTime);
         Metrics.logIdleMaintenance(MediaStore.VOLUME_EXTERNAL, helper.getItemCount(),
                 durationMillis, staleThumbnails, expiredMedia);
@@ -997,15 +1011,12 @@
     /**
      * Makes MediaScanner scan the given file.
      * @param file path of the file to be scanned
-     * @param uid  UID of the app that owns the file on the given path. If the file is scanned
-     *            on create, this UID will be used for updating owner package.
      *
      * Called from JNI in jni/MediaProviderWrapper.cpp
      */
     @Keep
-    public void scanFileForFuse(String file, int uid) {
-        final String callingPackage = getCachedCallingIdentityForFuse(uid).getPackageName();
-        scanFile(new File(file), REASON_DEMAND, callingPackage);
+    public void scanFileForFuse(String file) {
+        scanFile(new File(file), REASON_DEMAND);
     }
 
     /**
@@ -2301,34 +2312,6 @@
         Trace.endSection();
     }
 
-    private static @NonNull String[] sanitizePath(@Nullable String path) {
-        if (path == null) {
-            return new String[0];
-        } else {
-            final String[] segments = path.split("/");
-            // If the path corresponds to the top level directory, then we return an empty path
-            // which denotes the top level directory
-            if (segments.length == 0) {
-                return new String[] { "" };
-            }
-            for (int i = 0; i < segments.length; i++) {
-                segments[i] = sanitizeDisplayName(segments[i]);
-            }
-            return segments;
-        }
-    }
-
-    private static @Nullable String sanitizeDisplayName(@Nullable String name) {
-        if (name == null) {
-            return null;
-        } else if (name.startsWith(".")) {
-            // The resulting file must not be hidden.
-            return FileUtils.buildValidFatFilename("_" + name);
-        } else {
-            return FileUtils.buildValidFatFilename(name);
-        }
-    }
-
     /**
      * Sanity check that any requested {@link MediaColumns#DATA} paths actually
      * live on the storage volume being targeted.
@@ -5426,16 +5409,6 @@
         }
     }
 
-    @Nullable
-    private String getAbsoluteSanitizedPath(String path) {
-        final String[] pathSegments = sanitizePath(path);
-        if (pathSegments.length == 0) {
-            return null;
-        }
-        return path = "/" + String.join("/",
-                Arrays.copyOfRange(pathSegments, 1, pathSegments.length));
-    }
-
     /**
      * Calculates the ranges that need to be redacted for the given file and user that wants to
      * access the file.
diff --git a/src/com/android/providers/media/PermissionActivity.java b/src/com/android/providers/media/PermissionActivity.java
index 49a0062..371522a 100644
--- a/src/com/android/providers/media/PermissionActivity.java
+++ b/src/com/android/providers/media/PermissionActivity.java
@@ -147,8 +147,8 @@
 
         final AlertDialog.Builder builder = new AlertDialog.Builder(this);
         builder.setTitle(resolveTitleText());
-        builder.setPositiveButton(resolvePositiveText(), this::onPositiveAction);
-        builder.setNegativeButton(resolveNegativeText(), this::onNegativeAction);
+        builder.setPositiveButton(R.string.allow, this::onPositiveAction);
+        builder.setNegativeButton(R.string.deny, this::onNegativeAction);
         builder.setCancelable(false);
         builder.setView(bodyView);
 
diff --git a/src/com/android/providers/media/scan/ModernMediaScanner.java b/src/com/android/providers/media/scan/ModernMediaScanner.java
index 81a6a34..955c027 100644
--- a/src/com/android/providers/media/scan/ModernMediaScanner.java
+++ b/src/com/android/providers/media/scan/ModernMediaScanner.java
@@ -384,7 +384,8 @@
             final Bundle queryArgs = new Bundle();
             queryArgs.putString(ContentResolver.QUERY_ARG_SQL_SELECTION,
                     formatClause + " AND " + dataClause + " AND " + generationClause);
-            final String pathEscapedForLike = DatabaseUtils.escapeForLike(mRoot.getAbsolutePath());
+            final String pathEscapedForLike = DatabaseUtils.escapeForLike(
+                    FileUtils.getAbsoluteSanitizedPath(mRoot.getAbsolutePath()));
             queryArgs.putStringArray(ContentResolver.QUERY_ARG_SQL_SELECTION_ARGS,
                     new String[] {pathEscapedForLike + "/%", pathEscapedForLike});
             queryArgs.putString(ContentResolver.QUERY_ARG_SQL_SORT_ORDER,
diff --git a/src/com/android/providers/media/util/FileUtils.java b/src/com/android/providers/media/util/FileUtils.java
index b247f2e..c9cf1e2 100644
--- a/src/com/android/providers/media/util/FileUtils.java
+++ b/src/com/android/providers/media/util/FileUtils.java
@@ -701,4 +701,49 @@
             }
         }
     }
+
+    /** {@hide} **/
+    @Nullable
+    public static String getAbsoluteSanitizedPath(String path) {
+        final String[] pathSegments = sanitizePath(path);
+        if (pathSegments.length == 0) {
+            return null;
+        }
+        return path = "/" + String.join("/",
+                Arrays.copyOfRange(pathSegments, 1, pathSegments.length));
+    }
+
+    /** {@hide} */
+    public static @NonNull String[] sanitizePath(@Nullable String path) {
+        if (path == null) {
+            return new String[0];
+        } else {
+            final String[] segments = path.split("/");
+            // If the path corresponds to the top level directory, then we return an empty path
+            // which denotes the top level directory
+            if (segments.length == 0) {
+                return new String[] { "" };
+            }
+            for (int i = 0; i < segments.length; i++) {
+                segments[i] = sanitizeDisplayName(segments[i]);
+            }
+            return segments;
+        }
+    }
+
+    /**
+     * Sanitizes given name by appending '_' to make it non-hidden and mutating the file
+     * name to make it valid for a FAT filesystem.
+     * @hide
+     */
+    public static @Nullable String sanitizeDisplayName(@Nullable String name) {
+        if (name == null) {
+            return null;
+        } else if (name.startsWith(".")) {
+            // The resulting file must not be hidden.
+            return buildValidFatFilename("_" + name);
+        } else {
+            return buildValidFatFilename(name);
+        }
+    }
 }
diff --git a/tests/jni/FuseDaemonTest/FilePathAccessTestHelper/src/com/android/tests/fused/FilePathAccessTestHelper.java b/tests/jni/FuseDaemonTest/FilePathAccessTestHelper/src/com/android/tests/fused/FilePathAccessTestHelper.java
index f7af146..d13886a 100644
--- a/tests/jni/FuseDaemonTest/FilePathAccessTestHelper/src/com/android/tests/fused/FilePathAccessTestHelper.java
+++ b/tests/jni/FuseDaemonTest/FilePathAccessTestHelper/src/com/android/tests/fused/FilePathAccessTestHelper.java
@@ -25,7 +25,9 @@
 import static com.android.tests.fused.lib.TestUtils.OPEN_FILE_FOR_READ_QUERY;
 import static com.android.tests.fused.lib.TestUtils.OPEN_FILE_FOR_WRITE_QUERY;
 import static com.android.tests.fused.lib.TestUtils.QUERY_TYPE;
+import static com.android.tests.fused.lib.TestUtils.canOpenWithMediaProvider;
 import static com.android.tests.fused.lib.TestUtils.canOpen;
+import static com.android.tests.fused.lib.TestUtils.setContext;
 
 import android.app.Activity;
 import android.content.Intent;
@@ -49,6 +51,7 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        setContext(this);
         String queryType = getIntent().getStringExtra(QUERY_TYPE);
         queryType = queryType == null ? "null" : queryType;
         switch (queryType) {
@@ -115,9 +118,11 @@
                 } else if (queryType.equals(DELETE_FILE_QUERY)) {
                     returnStatus = file.delete();
                 } else if (queryType.equals(OPEN_FILE_FOR_READ_QUERY)) {
-                    returnStatus = canOpen(file, false /* forWrite */);
+                    returnStatus = canOpen(file, /* forWrite */ false)
+                            && canOpenWithMediaProvider(file, /* forWrite */ false);
                 } else if (queryType.equals(OPEN_FILE_FOR_WRITE_QUERY)) {
-                    returnStatus = canOpen(file, true /* forWrite */);
+                    returnStatus = canOpen(file, /* forWrite */ true)
+                            && canOpenWithMediaProvider(file, /* forWrite */ true);
                 }
             } catch(IOException e) {
                 Log.e(TAG, "Failed to access file: " + filePath + ". Query type: " + queryType, e);
diff --git a/tests/jni/FuseDaemonTest/libs/FuseDaemonTestLib/src/com/android/tests/fused/lib/TestUtils.java b/tests/jni/FuseDaemonTest/libs/FuseDaemonTestLib/src/com/android/tests/fused/lib/TestUtils.java
index 97e39d4..2bbb4b3 100644
--- a/tests/jni/FuseDaemonTest/libs/FuseDaemonTestLib/src/com/android/tests/fused/lib/TestUtils.java
+++ b/tests/jni/FuseDaemonTest/libs/FuseDaemonTestLib/src/com/android/tests/fused/lib/TestUtils.java
@@ -93,6 +93,8 @@
     private static final long POLLING_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(10);
     private static final long POLLING_SLEEP_MILLIS = 100;
 
+    @Nullable private static Context sContext;
+
     /**
      * Grants {@link Manifest.permission#GRANT_RUNTIME_PERMISSIONS} to the given package.
      */
@@ -255,9 +257,16 @@
     }
 
     public static ContentResolver getContentResolver() {
+        if (sContext != null) {
+            return sContext.getContentResolver();
+        }
         return getContext().getContentResolver();
     }
 
+    public static void setContext(Context context) {
+        sContext = context;
+    }
+
     /**
      * Queries {@link ContentResolver} for a file and returns the corresponding {@link Uri} for its
      * entry in the database. Returns {@code null} if file doesn't exist in the database.
@@ -381,7 +390,6 @@
         assertThat(fileUri).isNotNull();
         Log.i(TAG, "Uri: " + fileUri + ". Data: " + file.getPath());
         ParcelFileDescriptor pfd = getContentResolver().openFileDescriptor(fileUri, mode);
-        assertThat(pfd).isNotNull();
         return pfd;
     }
 
@@ -486,6 +494,19 @@
         }
     }
 
+    public static boolean canOpenWithMediaProvider(File file, boolean forWrite) {
+        try {
+            final Uri fileUri = getFileUri(file);
+            if (fileUri == null) {
+                return false;
+            }
+            getContentResolver().openFileDescriptor(fileUri, forWrite ? "w" : "r");
+            return true;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
     public static void pollForExternalStorageState() throws Exception {
         for (int i = 0; i < POLLING_TIMEOUT_MILLIS / POLLING_SLEEP_MILLIS; i++) {
             if(Environment.getExternalStorageState(Environment.getExternalStorageDirectory())