Merge "Add API for apps to query whether they have All Files Access" into rvc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
f46b9c9656
@@ -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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user