diff options
-rw-r--r-- | api/current.txt | 3 | ||||
-rw-r--r-- | core/java/android/os/Environment.java | 45 | ||||
-rw-r--r-- | core/tests/coretests/src/android/os/EnvironmentTest.java | 41 |
3 files changed, 87 insertions, 2 deletions
diff --git a/api/current.txt b/api/current.txt index 15f10faa4c4a..9935e6d35221 100644 --- a/api/current.txt +++ b/api/current.txt @@ -36154,6 +36154,8 @@ package android.os { method public static boolean isExternalStorageEmulated(@NonNull java.io.File); method public static boolean isExternalStorageLegacy(); method public static boolean isExternalStorageLegacy(@NonNull java.io.File); + method public static boolean isExternalStorageManager(); + method public static boolean isExternalStorageManager(@NonNull java.io.File); method public static boolean isExternalStorageRemovable(); method public static boolean isExternalStorageRemovable(@NonNull java.io.File); field public static String DIRECTORY_ALARMS; @@ -82232,4 +82234,3 @@ package org.xmlpull.v1.sax2 { } } - diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index 21a1e0f0a108..f2fb5b246f39 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -39,6 +39,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; import java.util.List; +import java.util.Objects; /** * Provides access to environment variables. @@ -1253,6 +1254,50 @@ public class Environment { uid, context.getOpPackageName()) == AppOpsManager.MODE_ALLOWED; } + /** + * Returns whether the calling app has All Files Access on the primary shared/external storage + * media. + * <p>Declaring the permission {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} isn't + * enough to gain the access. + * <p>To request access, use + * {@link android.provider.Settings#ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION}. + */ + public static boolean isExternalStorageManager() { + final File externalDir = sCurrentUser.getExternalDirs()[0]; + return isExternalStorageManager(externalDir); + } + + /** + * Returns whether the calling app has All Files Access at the given {@code path} + * <p>Declaring the permission {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} isn't + * enough to gain the access. + * <p>To request access, use + * {@link android.provider.Settings#ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION}. + */ + public static boolean isExternalStorageManager(@NonNull File path) { + final Context context = Objects.requireNonNull(AppGlobals.getInitialApplication()); + String packageName = Objects.requireNonNull(context.getPackageName()); + int uid = context.getApplicationInfo().uid; + + final AppOpsManager appOps = context.getSystemService(AppOpsManager.class); + final int opMode = + appOps.checkOpNoThrow(AppOpsManager.OP_MANAGE_EXTERNAL_STORAGE, uid, packageName); + + switch (opMode) { + case AppOpsManager.MODE_DEFAULT: + return PackageManager.PERMISSION_GRANTED + == context.checkPermission( + Manifest.permission.MANAGE_EXTERNAL_STORAGE, Process.myPid(), uid); + case AppOpsManager.MODE_ALLOWED: + return true; + case AppOpsManager.MODE_ERRORED: + case AppOpsManager.MODE_IGNORED: + return false; + default: + throw new IllegalStateException("Unknown AppOpsManager mode " + opMode); + } + } + static File getDirectory(String variableName, String defaultPath) { String path = System.getenv(variableName); return path == null ? new File(defaultPath) : new File(path); diff --git a/core/tests/coretests/src/android/os/EnvironmentTest.java b/core/tests/coretests/src/android/os/EnvironmentTest.java index d98ceaf57dd9..c0325caf1425 100644 --- a/core/tests/coretests/src/android/os/EnvironmentTest.java +++ b/core/tests/coretests/src/android/os/EnvironmentTest.java @@ -23,7 +23,10 @@ import static android.os.Environment.HAS_OTHER; import static android.os.Environment.classifyExternalStorageDirectory; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import android.app.AppOpsManager; import android.content.Context; import androidx.test.InstrumentationRegistry; @@ -40,10 +43,33 @@ import java.io.File; public class EnvironmentTest { private File dir; - private Context getContext() { + private static Context getContext() { return InstrumentationRegistry.getContext(); } + /** + * Sets {@code mode} for the given {@code ops} and the given {@code uid}. + * + * <p>This method drops shell permission identity. + */ + private static void setAppOpsModeForUid(int uid, int mode, String... ops) { + if (ops == null) { + return; + } + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity(); + try { + for (String op : ops) { + getContext().getSystemService(AppOpsManager.class).setUidMode(op, uid, mode); + } + } finally { + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .dropShellPermissionIdentity(); + } + } + @Before public void setUp() throws Exception { dir = getContext().getDir("testing", Context.MODE_PRIVATE); @@ -101,4 +127,17 @@ public class EnvironmentTest { Environment.buildPath(dir, "Taxes.pdf").createNewFile(); assertEquals(HAS_OTHER, classifyExternalStorageDirectory(dir)); } + + @Test + public void testIsExternalStorageManager() throws Exception { + assertFalse(Environment.isExternalStorageManager()); + try { + setAppOpsModeForUid(Process.myUid(), AppOpsManager.MODE_ALLOWED, + AppOpsManager.OPSTR_MANAGE_EXTERNAL_STORAGE); + assertTrue(Environment.isExternalStorageManager()); + } finally { + setAppOpsModeForUid(Process.myUid(), AppOpsManager.MODE_DEFAULT, + AppOpsManager.OPSTR_MANAGE_EXTERNAL_STORAGE); + } + } } |