diff --git a/api/system-current.txt b/api/system-current.txt index 692294d109acc..7a2f3a247ec3f 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4433,6 +4433,7 @@ package android.permission { ctor public RuntimePermissionPresenterService(); method public final void attachBaseContext(android.content.Context); method public final android.os.IBinder onBind(android.content.Intent); + method public abstract int onCountPermissionApps(java.util.List, boolean, boolean); method public abstract java.util.List onGetAppPermissions(java.lang.String); method public abstract void onRevokeRuntimePermission(java.lang.String, java.lang.String); field public static final java.lang.String SERVICE_INTERFACE = "android.permission.RuntimePermissionPresenterService"; diff --git a/core/java/android/permission/IRuntimePermissionPresenter.aidl b/core/java/android/permission/IRuntimePermissionPresenter.aidl index 693d21b075131..e95428ab2b026 100644 --- a/core/java/android/permission/IRuntimePermissionPresenter.aidl +++ b/core/java/android/permission/IRuntimePermissionPresenter.aidl @@ -26,4 +26,6 @@ import android.os.RemoteCallback; oneway interface IRuntimePermissionPresenter { void getAppPermissions(String packageName, in RemoteCallback callback); void revokeRuntimePermission(String packageName, String permissionName); + void countPermissionApps(in List permissionNames, boolean countOnlyGranted, + boolean countSystem, in RemoteCallback callback); } diff --git a/core/java/android/permission/RuntimePermissionPresenter.java b/core/java/android/permission/RuntimePermissionPresenter.java index ed9165e7ff878..3ce3c9db26232 100644 --- a/core/java/android/permission/RuntimePermissionPresenter.java +++ b/core/java/android/permission/RuntimePermissionPresenter.java @@ -16,6 +16,7 @@ package android.permission; +import static com.android.internal.util.Preconditions.checkCollectionElementsNotNull; import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; @@ -62,16 +63,31 @@ public final class RuntimePermissionPresenter { "android.permission.RuntimePermissionPresenter.key.result"; /** - * Listener for delivering a result. + * Listener for delivering the result of {@link #getAppPermissions}. */ - public interface OnResultCallback { + public interface OnGetAppPermissionResultCallback { /** - * The result for {@link #getAppPermissions(String, OnResultCallback, Handler)}. + * The result for {@link #getAppPermissions(String, OnGetAppPermissionResultCallback, + * Handler)}. + * * @param permissions The permissions list. */ void onGetAppPermissions(@NonNull List permissions); } + /** + * Listener for delivering the result of {@link #countPermissionApps}. + */ + public interface OnCountPermissionAppsResultCallback { + /** + * The result for {@link #countPermissionApps(List, boolean, + * OnCountPermissionAppsResultCallback, Handler)}. + * + * @param numApps The number of apps that have one of the permissions + */ + void onCountPermissionApps(int numApps); + } + private static final Object sLock = new Object(); @GuardedBy("sLock") @@ -106,7 +122,7 @@ public final class RuntimePermissionPresenter { * @param handler Handler on which to invoke the callback. */ public void getAppPermissions(@NonNull String packageName, - @NonNull OnResultCallback callback, @Nullable Handler handler) { + @NonNull OnGetAppPermissionResultCallback callback, @Nullable Handler handler) { checkNotNull(packageName); checkNotNull(callback); @@ -129,6 +145,25 @@ public final class RuntimePermissionPresenter { mRemoteService, packageName, permissionName)); } + /** + * Count how many apps have one of a set of permissions. + * + * @param permissionNames The permissions the app might have + * @param countOnlyGranted Count an app only if the permission is granted to the app + * @param countSystem Also count system apps + * @param callback Callback to receive the result + * @param handler Handler on which to invoke the callback + */ + public void countPermissionApps(@NonNull List permissionNames, + boolean countOnlyGranted, boolean countSystem, + @NonNull OnCountPermissionAppsResultCallback callback, @Nullable Handler handler) { + checkCollectionElementsNotNull(permissionNames, "permissionNames"); + checkNotNull(callback); + + mRemoteService.processMessage(obtainMessage(RemoteService::countPermissionApps, + mRemoteService, permissionNames, countOnlyGranted, countSystem, callback, handler)); + } + private static final class RemoteService extends Handler implements ServiceConnection { private static final long UNBIND_TIMEOUT_MILLIS = 10000; @@ -184,7 +219,7 @@ public final class RuntimePermissionPresenter { } private void getAppPermissions(@NonNull String packageName, - @NonNull OnResultCallback callback, @Nullable Handler handler) { + @NonNull OnGetAppPermissionResultCallback callback, @Nullable Handler handler) { final IRuntimePermissionPresenter remoteInstance; synchronized (mLock) { remoteInstance = mRemoteInstance; @@ -241,6 +276,45 @@ public final class RuntimePermissionPresenter { } } + private void countPermissionApps(@NonNull List permissionNames, + boolean countOnlyGranted, boolean countSystem, + @NonNull OnCountPermissionAppsResultCallback callback, @Nullable Handler handler) { + final IRuntimePermissionPresenter remoteInstance; + + synchronized (mLock) { + remoteInstance = mRemoteInstance; + } + if (remoteInstance == null) { + return; + } + + try { + remoteInstance.countPermissionApps(permissionNames, countOnlyGranted, countSystem, + new RemoteCallback(result -> { + final int numApps; + if (result != null) { + numApps = result.getInt(KEY_RESULT); + } else { + numApps = 0; + } + + if (handler != null) { + handler.post(() -> callback.onCountPermissionApps(numApps)); + } else { + callback.onCountPermissionApps(numApps); + } + }, this)); + } catch (RemoteException re) { + Log.e(TAG, "Error counting permission apps", re); + } + + scheduleUnbind(); + + synchronized (mLock) { + scheduleNextMessageIfNeededLocked(); + } + } + private void unbind() { synchronized (mLock) { if (mBound) { diff --git a/core/java/android/permission/RuntimePermissionPresenterService.java b/core/java/android/permission/RuntimePermissionPresenterService.java index e50fc5ab5b2aa..81ec7bed19afd 100644 --- a/core/java/android/permission/RuntimePermissionPresenterService.java +++ b/core/java/android/permission/RuntimePermissionPresenterService.java @@ -16,6 +16,7 @@ package android.permission; +import static com.android.internal.util.Preconditions.checkCollectionElementsNotNull; import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; @@ -81,6 +82,18 @@ public abstract class RuntimePermissionPresenterService extends Service { public abstract void onRevokeRuntimePermission(@NonNull String packageName, @NonNull String permissionName); + /** + * Count how many apps have one of a set of permissions. + * + * @param permissionNames The permissions the app might have + * @param countOnlyGranted Count an app only if the permission is granted to the app + * @param countSystem Also count system apps + * + * @return the number of apps that have one of the permissions + */ + public abstract int onCountPermissionApps(@NonNull List permissionNames, + boolean countOnlyGranted, boolean countSystem); + @Override public final IBinder onBind(Intent intent) { return new IRuntimePermissionPresenter.Stub() { @@ -106,6 +119,19 @@ public abstract class RuntimePermissionPresenterService extends Service { RuntimePermissionPresenterService.this, packageName, permissionName)); } + + @Override + public void countPermissionApps(List permissionNames, boolean countOnlyGranted, + boolean countSystem, RemoteCallback callback) { + checkCollectionElementsNotNull(permissionNames, "permissionNames"); + checkNotNull(callback, "callback"); + + mHandler.sendMessage( + obtainMessage( + RuntimePermissionPresenterService::countPermissionApps, + RuntimePermissionPresenterService.this, permissionNames, + countOnlyGranted, countSystem, callback)); + } }; } @@ -119,4 +145,13 @@ public abstract class RuntimePermissionPresenterService extends Service { callback.sendResult(null); } } + + private void countPermissionApps(@NonNull List permissionNames, + boolean countOnlyGranted, boolean countSystem, @NonNull RemoteCallback callback) { + int numApps = onCountPermissionApps(permissionNames, countOnlyGranted, countSystem); + + Bundle result = new Bundle(); + result.putInt(RuntimePermissionPresenter.KEY_RESULT, numApps); + callback.sendResult(result); + } } diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/PermissionsSummaryHelper.java b/packages/SettingsLib/src/com/android/settingslib/applications/PermissionsSummaryHelper.java index f2b97b405d8aa..2387b01d341d0 100644 --- a/packages/SettingsLib/src/com/android/settingslib/applications/PermissionsSummaryHelper.java +++ b/packages/SettingsLib/src/com/android/settingslib/applications/PermissionsSummaryHelper.java @@ -15,7 +15,6 @@ */ package com.android.settingslib.applications; -import android.annotation.NonNull; import android.content.Context; import android.permission.RuntimePermissionPresentationInfo; import android.permission.RuntimePermissionPresenter; @@ -31,37 +30,33 @@ public class PermissionsSummaryHelper { final PermissionsResultCallback callback) { final RuntimePermissionPresenter presenter = RuntimePermissionPresenter.getInstance(context); - presenter.getAppPermissions(pkg, new RuntimePermissionPresenter.OnResultCallback() { - @Override - public void onGetAppPermissions( - @NonNull List permissions) { - final int permissionCount = permissions.size(); + presenter.getAppPermissions(pkg, permissions -> { + final int permissionCount = permissions.size(); - int grantedStandardCount = 0; - int grantedAdditionalCount = 0; - int requestedCount = 0; - List grantedStandardLabels = new ArrayList<>(); + int grantedStandardCount = 0; + int grantedAdditionalCount = 0; + int requestedCount = 0; + List grantedStandardLabels = new ArrayList<>(); - for (int i = 0; i < permissionCount; i++) { - RuntimePermissionPresentationInfo permission = permissions.get(i); - requestedCount++; - if (permission.isGranted()) { - if (permission.isStandard()) { - grantedStandardLabels.add(permission.getLabel()); - grantedStandardCount++; - } else { - grantedAdditionalCount++; - } + for (int i = 0; i < permissionCount; i++) { + RuntimePermissionPresentationInfo permission = permissions.get(i); + requestedCount++; + if (permission.isGranted()) { + if (permission.isStandard()) { + grantedStandardLabels.add(permission.getLabel()); + grantedStandardCount++; + } else { + grantedAdditionalCount++; } } - - Collator collator = Collator.getInstance(); - collator.setStrength(Collator.PRIMARY); - Collections.sort(grantedStandardLabels, collator); - - callback.onPermissionSummaryResult(grantedStandardCount, requestedCount, - grantedAdditionalCount, grantedStandardLabels); } + + Collator collator = Collator.getInstance(); + collator.setStrength(Collator.PRIMARY); + Collections.sort(grantedStandardLabels, collator); + + callback.onPermissionSummaryResult(grantedStandardCount, requestedCount, + grantedAdditionalCount, grantedStandardLabels); }, null); }