diff --git a/res/values/strings.xml b/res/values/strings.xml index fe3935c1d58..16925d0d733 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -6142,6 +6142,12 @@ %d permissions granted + + + %d of %d permission granted + %d of %d permissions granted + + Some defaults set diff --git a/src/com/android/settings/applications/AppPermissionSettings.java b/src/com/android/settings/applications/AppPermissionSettings.java index 1776b3a42f4..16757d91545 100644 --- a/src/com/android/settings/applications/AppPermissionSettings.java +++ b/src/com/android/settings/applications/AppPermissionSettings.java @@ -21,6 +21,7 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.Resources; +import android.os.Build; import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceManager; @@ -177,6 +178,13 @@ public class AppPermissionSettings extends AppInfoWithHeader { } public static CharSequence getSummary(AppEntry appEntry, Context context) { + if (appEntry.info.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) { + AppPermissions appPerms = new AppPermissions(context, appEntry.info.packageName); + int count = appPerms.getPermissionCount(); + int grantedCount = appPerms.getGrantedPermissionsCount(); + return context.getResources().getQuantityString(R.plurals.runtime_permissions_summary, + count, grantedCount, count); + } AppSecurityPermissions asp = new AppSecurityPermissions(context, appEntry.info.packageName); int count = asp.getPermissionCount(); diff --git a/src/com/android/settings/applications/AppPermissions.java b/src/com/android/settings/applications/AppPermissions.java new file mode 100644 index 00000000000..6299921e510 --- /dev/null +++ b/src/com/android/settings/applications/AppPermissions.java @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.applications; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.PermissionInfo; +import android.os.Build; +import android.util.ArrayMap; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +/** + * Based off from + * packages/apps/PackageInstaller/src/com/android/packageinstaller/permission/AppPermissions.java + * Except we only care about the number rather than the details. + */ +public final class AppPermissions { + private static final String TAG = "AppPermissions"; + + private final ArrayMap mGroups = new ArrayMap<>(); + private final Context mContext; + private final PackageInfo mPackageInfo; + + public AppPermissions(Context context, String packageName) { + mContext = context; + mPackageInfo = getPackageInfo(packageName); + refresh(); + } + + private PackageInfo getPackageInfo(String packageName) { + try { + return mContext.getPackageManager().getPackageInfo(packageName, + PackageManager.GET_PERMISSIONS); + } catch (NameNotFoundException e) { + Log.e(TAG, "Unable to find " + packageName, e); + return null; + } + } + + public void refresh() { + if (mPackageInfo != null) { + loadPermissionGroups(); + } + } + + public int getPermissionCount() { + return mGroups.size(); + } + + public int getGrantedPermissionsCount() { + int ct = 0; + for (int i = 0; i < mGroups.size(); i++) { + if (mGroups.valueAt(i).areRuntimePermissionsGranted()) { + ct++; + } + } + return ct; + } + + private void loadPermissionGroups() { + mGroups.clear(); + if (mPackageInfo.requestedPermissions == null) { + return; + } + + final boolean appSupportsRuntimePermissions = appSupportsRuntime( + mPackageInfo.applicationInfo); + + for (int i = 0; i < mPackageInfo.requestedPermissions.length; i++) { + String requestedPerm = mPackageInfo.requestedPermissions[i]; + + final PermissionInfo permInfo; + try { + permInfo = mContext.getPackageManager().getPermissionInfo(requestedPerm, 0); + } catch (NameNotFoundException e) { + Log.w(TAG, "Unknown permission: " + requestedPerm); + continue; + } + + String permName = permInfo.name; + String groupName = permInfo.group != null ? permInfo.group : permName; + + PermissionGroup group = mGroups.get(groupName); + if (group == null) { + group = new PermissionGroup(); + mGroups.put(groupName, group); + } + + final boolean runtime = appSupportsRuntimePermissions + && permInfo.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS; + final boolean granted = (mPackageInfo.requestedPermissionsFlags[i] + & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0; + + Permission permission = new Permission(runtime, granted); + group.addPermission(permission, permName); + } + // Only care about runtime perms for now. + for (int i = mGroups.size() - 1; i >= 0; i--) { + if (!mGroups.valueAt(i).mHasRuntimePermissions) { + mGroups.removeAt(i); + } + } + } + + public static boolean appSupportsRuntime(ApplicationInfo info) { + return info.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1; + } + + private static final class PermissionGroup { + private final ArrayMap mPermissions = new ArrayMap<>(); + private boolean mHasRuntimePermissions; + + public boolean hasRuntimePermissions() { + return mHasRuntimePermissions; + } + + public boolean areRuntimePermissionsGranted() { + final int permissionCount = mPermissions.size(); + for (int i = 0; i < permissionCount; i++) { + Permission permission = mPermissions.valueAt(i); + if (permission.runtime && !permission.granted) { + return false; + } + } + return true; + } + + public List getPermissions() { + return new ArrayList<>(mPermissions.values()); + } + + void addPermission(Permission permission, String permName) { + mPermissions.put(permName, permission); + if (permission.runtime) { + mHasRuntimePermissions = true; + } + } + } + + private static final class Permission { + private final boolean runtime; + private boolean granted; + + public Permission(boolean runtime, boolean granted) { + this.runtime = runtime; + this.granted = granted; + } + } +}