Merge "Snap for 6873960 from dd9328b45dcd84ffc49273d671c3e03c1034f92e to android11-tests-release" into android11-tests-release
diff --git a/src/com/android/tradefed/device/NativeDevice.java b/src/com/android/tradefed/device/NativeDevice.java
index 034434e..90f91d2 100644
--- a/src/com/android/tradefed/device/NativeDevice.java
+++ b/src/com/android/tradefed/device/NativeDevice.java
@@ -109,6 +109,7 @@
 public class NativeDevice implements IManagedTestDevice {
 
     protected static final String SD_CARD = "/sdcard/";
+    protected static final String STORAGE_EMULATED = "/storage/emulated/";
     /**
      * Allow pauses of up to 2 minutes while receiving bugreport.
      * <p/>
@@ -1101,7 +1102,7 @@
     public boolean pullFile(final String remoteFilePath, final File localFile)
             throws DeviceNotAvailableException {
 
-        if (remoteFilePath.startsWith(SD_CARD)) {
+        if (isSdcardOrEmulated(remoteFilePath)) {
             ContentProviderHandler handler = getContentProvider();
             if (handler != null) {
                 return handler.pullFile(remoteFilePath, localFile);
@@ -1209,7 +1210,7 @@
     @Override
     public boolean pushFile(final File localFile, final String remoteFilePath)
             throws DeviceNotAvailableException {
-        if (remoteFilePath.startsWith(SD_CARD)) {
+        if (isSdcardOrEmulated(remoteFilePath)) {
             ContentProviderHandler handler = getContentProvider();
             if (handler != null) {
                 return handler.pushFile(localFile, remoteFilePath);
@@ -1284,7 +1285,7 @@
     /** {@inheritDoc} */
     @Override
     public boolean doesFileExist(String deviceFilePath) throws DeviceNotAvailableException {
-        if (deviceFilePath.startsWith(SD_CARD)) {
+        if (isSdcardOrEmulated(deviceFilePath)) {
             ContentProviderHandler handler = getContentProvider();
             if (handler != null) {
                 CLog.d("Delegating check to ContentProvider doesFileExist(%s)", deviceFilePath);
@@ -1300,7 +1301,7 @@
     /** {@inheritDoc} */
     @Override
     public void deleteFile(String deviceFilePath) throws DeviceNotAvailableException {
-        if (deviceFilePath.startsWith(SD_CARD)) {
+        if (isSdcardOrEmulated(deviceFilePath)) {
             ContentProviderHandler handler = getContentProvider();
             if (handler != null) {
                 if (handler.deleteFile(deviceFilePath)) {
@@ -1633,7 +1634,7 @@
     @Override
     public boolean pullDir(String deviceFilePath, File localDir)
             throws DeviceNotAvailableException {
-        if (deviceFilePath.startsWith(SD_CARD)) {
+        if (isSdcardOrEmulated(deviceFilePath)) {
             ContentProviderHandler handler = getContentProvider();
             if (handler != null) {
                 return handler.pullDir(deviceFilePath, localDir);
@@ -1686,6 +1687,11 @@
         return true;
     }
 
+    /** Checks whether path is external storage path. */
+    private boolean isSdcardOrEmulated(String path) {
+        return path.startsWith(SD_CARD) || path.startsWith(STORAGE_EMULATED);
+    }
+
     /**
      * {@inheritDoc}
      */
diff --git a/tests/src/com/android/tradefed/device/TestDeviceTest.java b/tests/src/com/android/tradefed/device/TestDeviceTest.java
index e6007fd..f4e8aee 100644
--- a/tests/src/com/android/tradefed/device/TestDeviceTest.java
+++ b/tests/src/com/android/tradefed/device/TestDeviceTest.java
@@ -4747,64 +4747,43 @@
     }
 
     /**
-     * Test {@link TestDevice#doesFileExist(String)} when the file exists on an sdcard from another
-     * user.
+     * Test {@link TestDevice#doesFileExist(String)} using content provider when the file is in
+     * external storage path.
      */
     public void testDoesFileExists_sdcard() throws Exception {
-        mTestDevice =
-                new TestableTestDevice() {
-                    @Override
-                    public int getCurrentUser()
-                            throws DeviceNotAvailableException, DeviceRuntimeException {
-                        return 10;
-                    }
-                };
-        injectShellResponse("ls \"/storage/emulated/10/file\"", "file");
+        mTestDevice = createTestDevice();
+
+        TestableTestDevice spy = (TestableTestDevice) Mockito.spy(mTestDevice);
+        ContentProviderHandler cp = Mockito.mock(ContentProviderHandler.class);
+        doReturn(cp).when(spy).getContentProvider();
+
+        final String fakeFile = "/sdcard/file";
+        final String targetFilePath = "/storage/emulated/10/file";
+
+        doReturn("").when(spy).executeShellCommand(Mockito.contains("content query --user 10"));
+
         EasyMock.replay(mMockIDevice);
-        assertTrue(mTestDevice.doesFileExist("/sdcard/file"));
+        spy.doesFileExist(fakeFile);
         EasyMock.verify(mMockIDevice);
+
+        verify(spy, times(1)).getContentProvider();
+        verify(cp, times(1)).doesFileExist(targetFilePath);
     }
 
     /** Push a file using the content provider. */
     public void testPushFile_contentProvider() throws Exception {
-        mTestDevice =
-                new TestableTestDevice() {
-                    @Override
-                    public int getApiLevel() throws DeviceNotAvailableException {
-                        return 29;
-                    }
-
-                    @Override
-                    public int getCurrentUser()
-                            throws DeviceNotAvailableException, DeviceRuntimeException {
-                        return 10;
-                    }
-
-                    @Override
-                    public boolean isPackageInstalled(String packageName, String userId)
-                            throws DeviceNotAvailableException {
-                        return false;
-                    }
-                };
+        mTestDevice = createTestDevice();
         TestableTestDevice spy = (TestableTestDevice) Mockito.spy(mTestDevice);
+        setupContentProvider(spy);
+
         final String fakeRemotePath = "/sdcard/";
         File tmpFile = FileUtil.createTempFile("push", ".test");
-        doReturn(null)
-                .when(spy)
-                .installPackage(Mockito.any(), Mockito.anyBoolean(), Mockito.anyBoolean());
-        CommandResult setLegacy = new CommandResult(CommandStatus.SUCCESS);
-        doReturn(setLegacy).when(spy).executeShellV2Command(Mockito.contains("cmd appops set"));
-
-        CommandResult getLegacy = new CommandResult(CommandStatus.SUCCESS);
-        getLegacy.setStdout("LEGACY_STORAGE: allow");
-        doReturn(getLegacy).when(spy).executeShellV2Command(Mockito.contains("cmd appops get"));
 
         CommandResult writeContent = new CommandResult(CommandStatus.SUCCESS);
         writeContent.setStdout("");
         doReturn(writeContent)
                 .when(spy)
                 .executeShellV2Command(Mockito.contains("content write"), (File) Mockito.any());
-        doReturn(null).when(spy).uninstallPackage(Mockito.eq("android.tradefed.contentprovider"));
         EasyMock.replay(mMockIDevice);
         try {
             boolean res = spy.pushFile(tmpFile, fakeRemotePath);
@@ -4825,37 +4804,12 @@
 
     /** Push a file using the content provider. */
     public void testPushFile_contentProvider_notFound() throws Exception {
-        mTestDevice =
-                new TestableTestDevice() {
-                    @Override
-                    public int getApiLevel() throws DeviceNotAvailableException {
-                        return 29;
-                    }
-
-                    @Override
-                    public int getCurrentUser()
-                            throws DeviceNotAvailableException, DeviceRuntimeException {
-                        return 10;
-                    }
-
-                    @Override
-                    public boolean isPackageInstalled(String packageName, String userId)
-                            throws DeviceNotAvailableException {
-                        return false;
-                    }
-                };
+        mTestDevice = createTestDevice();
         TestableTestDevice spy = (TestableTestDevice) Mockito.spy(mTestDevice);
+        setupContentProvider(spy);
+
         final String fakeRemotePath = "/sdcard/";
         File tmpFile = FileUtil.createTempFile("push", ".test");
-        doReturn(null)
-                .when(spy)
-                .installPackage(Mockito.any(), Mockito.anyBoolean(), Mockito.anyBoolean());
-        CommandResult setLegacy = new CommandResult(CommandStatus.SUCCESS);
-        doReturn(setLegacy).when(spy).executeShellV2Command(Mockito.contains("cmd appops set"));
-
-        CommandResult getLegacy = new CommandResult(CommandStatus.SUCCESS);
-        getLegacy.setStdout("LEGACY_STORAGE: allow");
-        doReturn(getLegacy).when(spy).executeShellV2Command(Mockito.contains("cmd appops get"));
 
         CommandResult writeContent = new CommandResult(CommandStatus.SUCCESS);
         writeContent.setStdout("");
@@ -4901,4 +4855,38 @@
                                 EasyMock.eq(property)))
                 .andReturn(stubResult);
     }
+
+    private void setupContentProvider(TestableTestDevice spy) throws Exception {
+        doReturn(null)
+                .when(spy)
+                .installPackage(Mockito.any(), Mockito.anyBoolean(), Mockito.anyBoolean());
+        CommandResult setLegacy = new CommandResult(CommandStatus.SUCCESS);
+        doReturn(setLegacy).when(spy).executeShellV2Command(Mockito.contains("cmd appops set"));
+
+        CommandResult getLegacy = new CommandResult(CommandStatus.SUCCESS);
+        getLegacy.setStdout("LEGACY_STORAGE: allow");
+        doReturn(getLegacy).when(spy).executeShellV2Command(Mockito.contains("cmd appops get"));
+
+        doReturn(null).when(spy).uninstallPackage(Mockito.eq("android.tradefed.contentprovider"));
+    }
+
+    private TestableTestDevice createTestDevice() {
+        return new TestableTestDevice() {
+            @Override
+            public int getApiLevel() throws DeviceNotAvailableException {
+                return 29;
+            }
+
+            @Override
+            public int getCurrentUser() throws DeviceNotAvailableException, DeviceRuntimeException {
+                return 10;
+            }
+
+            @Override
+            public boolean isPackageInstalled(String packageName, String userId)
+                    throws DeviceNotAvailableException {
+                return false;
+            }
+        };
+    }
 }
diff --git a/util-apps/ContentProvider/main/AndroidManifest.xml b/util-apps/ContentProvider/main/AndroidManifest.xml
index ac37e68..15cb3fa 100644
--- a/util-apps/ContentProvider/main/AndroidManifest.xml
+++ b/util-apps/ContentProvider/main/AndroidManifest.xml
@@ -19,6 +19,7 @@
 
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
 
     <application>
         <provider