am c5ff0020: Merge "Add API to hint whether to show on-board UI before a permission request." into mnc-dev
* commit 'c5ff0020a2467e0b7aed590d790b5a1b4b082f56':
Add API to hint whether to show on-board UI before a permission request.
diff --git a/api/current.txt b/api/current.txt
index f31593d..707329c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3513,6 +3513,7 @@
method public deprecated void setTitleColor(int);
method public void setVisible(boolean);
method public final void setVolumeControlStream(int);
+ method public boolean shouldShowRequestPermissionRationale(java.lang.String);
method public boolean shouldUpRecreateTask(android.content.Intent);
method public final deprecated void showDialog(int);
method public final deprecated boolean showDialog(int, android.os.Bundle);
diff --git a/api/system-current.txt b/api/system-current.txt
index cf6d0f6..9e99562 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3599,6 +3599,7 @@
method public deprecated void setTitleColor(int);
method public void setVisible(boolean);
method public final void setVolumeControlStream(int);
+ method public boolean shouldShowRequestPermissionRationale(java.lang.String);
method public boolean shouldUpRecreateTask(android.content.Intent);
method public final deprecated void showDialog(int);
method public final deprecated boolean showDialog(int, android.os.Bundle);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 49f5099..a8eaaae 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3746,6 +3746,7 @@
*
* @see #onRequestPermissionsResult(int, String[], int[])
* @see #checkSelfPermission(String)
+ * @see #canShowRequestPermissionRationale(String)
*/
public final void requestPermissions(@NonNull String[] permissions, int requestCode) {
Intent intent = getPackageManager().buildRequestPermissionsIntent(permissions);
@@ -3770,6 +3771,30 @@
}
/**
+ * Gets whether you should show UI with rationale for requesting a permission.
+ * You should do this only if you do not have the permission and the context in
+ * which the permission is requested does not clearly communicate to the user
+ * what would be the benefit from granting this permission.
+ * <p>
+ * For example, if you write a camera app, requesting the camera permission
+ * would be expected by the user and no rationale for why it is requested is
+ * needed. If however, the app needs location for tagging photos then a non-tech
+ * savvy user may wonder how location is related to taking photos. In this case
+ * you may choose to show UI with rationale of requesting this permission.
+ * </p>
+ *
+ * @param permission A permission your app wants to request.
+ * @return Whether you can show permission rationale UI.
+ *
+ * @see #checkSelfPermission(String)
+ * @see #requestPermissions(String[], int)
+ * @see #onRequestPermissionsResult(int, String[], int[])
+ */
+ public boolean shouldShowRequestPermissionRationale(String permission) {
+ return getPackageManager().shouldShowRequestPermissionRationale(permission);
+ }
+
+ /**
* Same as calling {@link #startActivityForResult(Intent, int, Bundle)}
* with no options.
*
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 04f6430..41e3db8 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -486,6 +486,16 @@
}
@Override
+ public boolean shouldShowRequestPermissionRationale(String permission) {
+ try {
+ return mPM.shouldShowRequestPermissionRationale(permission,
+ mContext.getPackageName(), mContext.getUserId());
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
public int checkSignatures(String pkg1, String pkg2) {
try {
return mPM.checkSignatures(pkg1, pkg2);
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index ddff782..00b8c71 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -105,6 +105,9 @@
void updatePermissionFlags(String permissionName, String packageName, int flagMask,
int flagValues, int userId);
+ boolean shouldShowRequestPermissionRationale(String permissionName,
+ String packageName, int userId);
+
boolean isProtectedBroadcast(String actionName);
int checkSignatures(String pkg1, String pkg2);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 2ca0306..45245e4 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2539,6 +2539,19 @@
@NonNull UserHandle user);
/**
+ * Gets whether you should show UI with rationale for requesting a permission.
+ * You should do this only if you do not have the permission and the context in
+ * which the permission is requested does not clearly communicate to the user
+ * what would be the benefit from grating this permission.
+ *
+ * @param permission A permission your app wants to request.
+ * @return Whether you can show permission rationale UI.
+ *
+ * @hide
+ */
+ public abstract boolean shouldShowRequestPermissionRationale(String permission);
+
+ /**
* Returns an {@link android.content.Intent} suitable for passing to
* {@link android.app.Activity#startActivityForResult(android.content.Intent, int)}
* which prompts the user to grant permissions to this application.
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9b619c7..47e3963 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3360,6 +3360,46 @@
}
@Override
+ public boolean shouldShowRequestPermissionRationale(String permissionName,
+ String packageName, int userId) {
+ if (UserHandle.getCallingUserId() != userId) {
+ mContext.enforceCallingPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ "canShowRequestPermissionRationale for user " + userId);
+ }
+
+ final int uid = getPackageUid(packageName, userId);
+ if (UserHandle.getAppId(getCallingUid()) != UserHandle.getAppId(uid)) {
+ return false;
+ }
+
+ if (checkPermission(permissionName, packageName, userId)
+ == PackageManager.PERMISSION_GRANTED) {
+ return false;
+ }
+
+ final int flags;
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ flags = getPermissionFlags(permissionName,
+ packageName, userId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+
+ final int fixedFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
+ | PackageManager.FLAG_PERMISSION_POLICY_FIXED
+ | PackageManager.FLAG_PERMISSION_USER_FIXED;
+
+ if ((flags & fixedFlags) != 0) {
+ return false;
+ }
+
+ return (flags & PackageManager.FLAG_PERMISSION_USER_SET) != 0;
+ }
+
+ @Override
public boolean isProtectedBroadcast(String actionName) {
synchronized (mPackages) {
return mProtectedBroadcasts.contains(actionName);
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index bf1ea4d..3b7aa9f 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -218,6 +218,12 @@
throw new UnsupportedOperationException();
}
+ /** @hide */
+ @Override
+ public boolean shouldShowRequestPermissionRationale(String permission) {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public int checkSignatures(String pkg1, String pkg2) {
throw new UnsupportedOperationException();