Merge "Add API for apps to query whether they have All Files Access" into rvc-dev am: f46b9c9656 am: cae4001988

Change-Id: I0e4f4e35e21687aa1b2b9cf8a17c86278fbd6261
This commit is contained in:
Automerger Merge Worker
2020-03-10 17:41:14 +00:00
3 changed files with 87 additions and 2 deletions

View File

@@ -36154,6 +36154,8 @@ package android.os {
method public static boolean isExternalStorageEmulated(@NonNull java.io.File); method public static boolean isExternalStorageEmulated(@NonNull java.io.File);
method public static boolean isExternalStorageLegacy(); method public static boolean isExternalStorageLegacy();
method public static boolean isExternalStorageLegacy(@NonNull java.io.File); 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();
method public static boolean isExternalStorageRemovable(@NonNull java.io.File); method public static boolean isExternalStorageRemovable(@NonNull java.io.File);
field public static String DIRECTORY_ALARMS; field public static String DIRECTORY_ALARMS;
@@ -82232,4 +82234,3 @@ package org.xmlpull.v1.sax2 {
} }
} }

View File

@@ -39,6 +39,7 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Objects;
/** /**
* Provides access to environment variables. * Provides access to environment variables.
@@ -1253,6 +1254,50 @@ public class Environment {
uid, context.getOpPackageName()) == AppOpsManager.MODE_ALLOWED; 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) { static File getDirectory(String variableName, String defaultPath) {
String path = System.getenv(variableName); String path = System.getenv(variableName);
return path == null ? new File(defaultPath) : new File(path); return path == null ? new File(defaultPath) : new File(path);

View File

@@ -23,7 +23,10 @@ import static android.os.Environment.HAS_OTHER;
import static android.os.Environment.classifyExternalStorageDirectory; import static android.os.Environment.classifyExternalStorageDirectory;
import static org.junit.Assert.assertEquals; 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 android.content.Context;
import androidx.test.InstrumentationRegistry; import androidx.test.InstrumentationRegistry;
@@ -40,10 +43,33 @@ import java.io.File;
public class EnvironmentTest { public class EnvironmentTest {
private File dir; private File dir;
private Context getContext() { private static Context getContext() {
return InstrumentationRegistry.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 @Before
public void setUp() throws Exception { public void setUp() throws Exception {
dir = getContext().getDir("testing", Context.MODE_PRIVATE); dir = getContext().getDir("testing", Context.MODE_PRIVATE);
@@ -101,4 +127,17 @@ public class EnvironmentTest {
Environment.buildPath(dir, "Taxes.pdf").createNewFile(); Environment.buildPath(dir, "Taxes.pdf").createNewFile();
assertEquals(HAS_OTHER, classifyExternalStorageDirectory(dir)); 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);
}
}
} }