summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AndroidManifest.xml1
-rw-r--r--res/drawable/ic_perm_device_info.xml24
-rw-r--r--res/menu/toggle_legacy_permissions.xml24
-rw-r--r--res/values/strings.xml6
-rw-r--r--src/com/android/packageinstaller/permission/model/AppPermissionGroup.java535
-rw-r--r--src/com/android/packageinstaller/permission/model/AppPermissions.java18
-rw-r--r--src/com/android/packageinstaller/permission/model/PermissionApps.java28
-rw-r--r--src/com/android/packageinstaller/permission/model/PermissionGroup.java467
-rw-r--r--src/com/android/packageinstaller/permission/model/PermissionGroups.java222
-rw-r--r--src/com/android/packageinstaller/permission/ui/AppPermissionsFragment.java70
-rw-r--r--src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java12
-rw-r--r--src/com/android/packageinstaller/permission/ui/ManagePermissionsActivity.java45
-rw-r--r--src/com/android/packageinstaller/permission/ui/ManagePermissionsFragment.java216
-rw-r--r--src/com/android/packageinstaller/permission/ui/PermissionAppsFragment.java13
-rw-r--r--src/com/android/packageinstaller/permission/utils/SafetyNetLogger.java10
-rw-r--r--src/com/android/packageinstaller/permission/utils/Utils.java20
16 files changed, 1189 insertions, 522 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index dedf0c48..0a39a43d 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -81,6 +81,7 @@
android:theme="@style/Settings"
android:permission="android.permission.GRANT_REVOKE_PERMISSIONS">
<intent-filter>
+ <action android:name="android.intent.action.MANAGE_PERMISSIONS" />
<action android:name="android.intent.action.MANAGE_APP_PERMISSIONS" />
<action android:name="android.intent.action.MANAGE_PERMISSION_APPS" />
<category android:name="android.intent.category.DEFAULT" />
diff --git a/res/drawable/ic_perm_device_info.xml b/res/drawable/ic_perm_device_info.xml
new file mode 100644
index 00000000..ef91c746
--- /dev/null
+++ b/res/drawable/ic_perm_device_info.xml
@@ -0,0 +1,24 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M26.0,14.0l-4.0,0.0l0.0,4.0l4.0,0.0l0.0,-4.0zm0.0,8.0l-4.0,0.0l0.0,12.0l4.0,0.0L26.0,22.0zm8.0,-19.98L14.0,2.0c-2.21,0.0 -4.0,1.79 -4.0,4.0l0.0,36.0c0.0,2.21 1.79,4.0 4.0,4.0l20.0,0.0c2.21,0.0 4.0,-1.79 4.0,-4.0L38.0,6.0c0.0,-2.21 -1.79,-3.98 -4.0,-3.98zM34.0,38.0L14.0,38.0L14.0,10.0l20.0,0.0l0.0,28.0z"/>
+</vector>
diff --git a/res/menu/toggle_legacy_permissions.xml b/res/menu/toggle_legacy_permissions.xml
new file mode 100644
index 00000000..544c4793
--- /dev/null
+++ b/res/menu/toggle_legacy_permissions.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item
+ android:id="@+id/toggle_legacy_permissions"
+ android:title="@string/show_legacy_permissions">
+ </item>
+
+</menu>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 38f70273..955c0e5d 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -215,4 +215,10 @@
<!-- Warning for turning off permissions on older apps -->
<string name="old_sdk_deny_warning">This app was designed for an older version of Android. Denying permission may cause it to no longer function as intended.</string>
+ <!-- Label for the menu option to show legacy permissions [CHAR LIMIT=40] -->
+ <string name="show_legacy_permissions">Show legacy</string>
+
+ <!-- Label for the menu option to hide legacy permissions [CHAR LIMIT=40] -->
+ <string name="hide_legacy_permissions">Hide legacy</string>
+
</resources>
diff --git a/src/com/android/packageinstaller/permission/model/AppPermissionGroup.java b/src/com/android/packageinstaller/permission/model/AppPermissionGroup.java
new file mode 100644
index 00000000..e3c9160a
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/model/AppPermissionGroup.java
@@ -0,0 +1,535 @@
+/*
+ * 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.packageinstaller.permission.model;
+
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageItemInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionGroupInfo;
+import android.content.pm.PermissionInfo;
+import android.os.Build;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+
+import com.android.packageinstaller.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class AppPermissionGroup implements Comparable<AppPermissionGroup> {
+ private static final String PLATFORM_PACKAGE_NAME = "android";
+
+ private static final String KILL_REASON_APP_OP_CHANGE = "Permission related app op changed";
+
+ private final Context mContext;
+ private final UserHandle mUserHandle;
+ private final PackageManager mPackageManager;
+ private final AppOpsManager mAppOps;
+ private final ActivityManager mActivityManager;
+
+ private final PackageInfo mPackageInfo;
+ private final String mName;
+ private final String mDeclaringPackage;
+ private final CharSequence mLabel;
+ private final ArrayMap<String, Permission> mPermissions = new ArrayMap<>();
+ private final String mIconPkg;
+ private final int mIconResId;
+
+ private final boolean mAppSupportsRuntimePermissions;
+
+ public static AppPermissionGroup create(Context context, PackageInfo packageInfo,
+ String permissionName) {
+ PermissionInfo permissionInfo;
+ try {
+ permissionInfo = context.getPackageManager().getPermissionInfo(permissionName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ return null;
+ }
+
+ if (permissionInfo.protectionLevel != PermissionInfo.PROTECTION_DANGEROUS) {
+ return null;
+ }
+
+ PackageItemInfo groupInfo = permissionInfo;
+ if (permissionInfo.group != null) {
+ try {
+ groupInfo = context.getPackageManager().getPermissionGroupInfo(
+ permissionInfo.group, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ /* ignore */
+ }
+ }
+
+ List<PermissionInfo> permissionInfos = null;
+ if (groupInfo instanceof PermissionGroupInfo) {
+ try {
+ permissionInfos = context.getPackageManager().queryPermissionsByGroup(
+ groupInfo.name, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ /* ignore */
+ }
+ }
+
+ return create(context, packageInfo, groupInfo, permissionInfos);
+ }
+
+ public static AppPermissionGroup create(Context context, PackageInfo packageInfo,
+ PackageItemInfo groupInfo, List<PermissionInfo> permissionInfos) {
+
+ AppPermissionGroup group = new AppPermissionGroup(context, packageInfo, groupInfo.name,
+ groupInfo.packageName, groupInfo.loadLabel(context.getPackageManager()),
+ groupInfo.packageName, groupInfo.icon);
+
+ if (groupInfo instanceof PermissionInfo) {
+ permissionInfos = new ArrayList<>();
+ permissionInfos.add((PermissionInfo) groupInfo);
+ }
+
+ if (permissionInfos == null || permissionInfos.isEmpty()) {
+ return null;
+ }
+
+ final int permissionCount = packageInfo.requestedPermissions.length;
+ for (int i = 0; i < permissionCount; i++) {
+ String requestedPermission = packageInfo.requestedPermissions[i];
+
+ PermissionInfo requestedPermissionInfo = null;
+
+ for (PermissionInfo permissionInfo : permissionInfos) {
+ if (requestedPermission.equals(permissionInfo.name)) {
+ requestedPermissionInfo = permissionInfo;
+ break;
+ }
+ }
+
+ if (requestedPermissionInfo == null) {
+ continue;
+ }
+
+ // Collect only runtime permissions.
+ if (requestedPermissionInfo.protectionLevel != PermissionInfo.PROTECTION_DANGEROUS) {
+ continue;
+ }
+
+ // Don't allow toggle of non platform defined permissions for legacy apps via app ops.
+ if (packageInfo.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1
+ && !PLATFORM_PACKAGE_NAME.equals(requestedPermissionInfo.packageName)) {
+ continue;
+ }
+
+ final boolean granted = (packageInfo.requestedPermissionsFlags[i]
+ & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0;
+
+ final int appOp = PLATFORM_PACKAGE_NAME.equals(requestedPermissionInfo.packageName)
+ ? AppOpsManager.permissionToOpCode(requestedPermissionInfo.name)
+ : AppOpsManager.OP_NONE;
+
+ final boolean appOpAllowed = appOp != AppOpsManager.OP_NONE
+ && context.getSystemService(AppOpsManager.class).checkOp(appOp,
+ packageInfo.applicationInfo.uid, packageInfo.packageName)
+ == AppOpsManager.MODE_ALLOWED;
+
+ final int flags = context.getPackageManager().getPermissionFlags(
+ requestedPermission, packageInfo.packageName,
+ new UserHandle(context.getUserId()));
+
+ Permission permission = new Permission(requestedPermission, granted,
+ appOp, appOpAllowed, flags);
+ group.addPermission(permission);
+ }
+
+ return group;
+ }
+
+ private AppPermissionGroup(Context context, PackageInfo packageInfo, String name,
+ String declaringPackage, CharSequence label, String iconPkg, int iconResId) {
+ mContext = context;
+ mUserHandle = new UserHandle(mContext.getUserId());
+ mPackageManager = mContext.getPackageManager();
+ mPackageInfo = packageInfo;
+ mAppSupportsRuntimePermissions = packageInfo.applicationInfo
+ .targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1;
+ mAppOps = context.getSystemService(AppOpsManager.class);
+ mActivityManager = context.getSystemService(ActivityManager.class);
+ mDeclaringPackage = declaringPackage;
+ mName = name;
+ mLabel = label;
+ mIconPkg = iconPkg;
+ mIconResId = iconResId != 0 ? iconResId : R.drawable.ic_perm_device_info;
+ }
+
+ public boolean hasRuntimePermission() {
+ return mAppSupportsRuntimePermissions;
+ }
+
+ public boolean hasAppOpPermission() {
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ Permission permission = mPermissions.valueAt(i);
+ if (permission.getAppOp() != AppOpsManager.OP_NONE) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public PackageInfo getApp() {
+ return mPackageInfo;
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public String getDeclaringPackage() {
+ return mDeclaringPackage;
+ }
+
+ public String getIconPkg() {
+ return mIconPkg;
+ }
+
+ public int getIconResId() {
+ return mIconResId;
+ }
+
+ public CharSequence getLabel() {
+ return mLabel;
+ }
+
+ public boolean hasPermission(String permission) {
+ return mPermissions.get(permission) != null;
+ }
+
+ public boolean areRuntimePermissionsGranted() {
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ Permission permission = mPermissions.valueAt(i);
+ if (mAppSupportsRuntimePermissions) {
+ if (!permission.isGranted()) {
+ return false;
+ }
+ } else if (permission.isGranted() && permission.getAppOp()
+ != AppOpsManager.OP_NONE && !permission.isAppOpAllowed()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean grantRuntimePermissions(boolean fixedByTheUser) {
+ final boolean isSharedUser = mPackageInfo.sharedUserId != null;
+ final int uid = mPackageInfo.applicationInfo.uid;
+
+ // We toggle permissions only to apps that support runtime
+ // permissions, otherwise we toggle the app op corresponding
+ // to the permission if the permission is granted to the app.
+ for (Permission permission : mPermissions.values()) {
+ if (mAppSupportsRuntimePermissions) {
+ // Grant the permission if needed.
+ if (!permission.isGranted()) {
+ permission.setGranted(true);
+ mPackageManager.grantRuntimePermission(mPackageInfo.packageName,
+ permission.getName(), new UserHandle(mContext.getUserId()));
+ }
+
+ // Update the permission flags.
+ if (!fixedByTheUser) {
+ // Now the apps can ask for the permission as the user
+ // no longer has it fixed in a denied state.
+ if (permission.isUserFixed() || !permission.isUserSet()) {
+ permission.setUserFixed(false);
+ permission.setUserSet(true);
+ mPackageManager.updatePermissionFlags(permission.getName(),
+ mPackageInfo.packageName,
+ PackageManager.FLAG_PERMISSION_USER_FIXED
+ | PackageManager.FLAG_PERMISSION_USER_SET,
+ PackageManager.FLAG_PERMISSION_USER_SET,
+ mUserHandle);
+ }
+ }
+
+ // Enable the permission app op.
+ if (permission.hasAppOp() && !permission.isAppOpAllowed()) {
+ permission.setAppOpAllowed(true);
+ mAppOps.setMode(permission.getAppOp(), android.os.Process.myUid(),
+ mPackageInfo.packageName, AppOpsManager.MODE_ALLOWED);
+ }
+ } else {
+ // Legacy apps cannot have a not granted permission but just in case.
+ // Also if the permissions has no corresponding app op, then it is a
+ // third-party one and we do not offer toggling of such permissions.
+ if (!permission.isGranted() || !permission.hasAppOp()) {
+ continue;
+ }
+
+ if (!permission.isAppOpAllowed()) {
+ permission.setAppOpAllowed(true);
+ // It this is a shared user we want to enable the app op for all
+ // packages in the shared user to match the behavior of this
+ // shared user having a runtime permission.
+ if (isSharedUser) {
+ // Enable the app op.
+ String[] packageNames = mPackageManager.getPackagesForUid(uid);
+ for (String packageName : packageNames) {
+ mAppOps.setMode(permission.getAppOp(), uid, packageName,
+ AppOpsManager.MODE_ALLOWED);
+ }
+ } else {
+ // Enable the app op.
+ mAppOps.setMode(permission.getAppOp(), uid, mPackageInfo.packageName,
+ AppOpsManager.MODE_ALLOWED);
+ }
+
+ // Mark that the permission should not be be granted on upgrade
+ // when the app begins supporting runtime permissions.
+ if (permission.shouldRevokeOnUpgrade()) {
+ permission.setRevokeOnUpgrade(false);
+ mPackageManager.updatePermissionFlags(permission.getName(),
+ mPackageInfo.packageName,
+ PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE,
+ 0, mUserHandle);
+ }
+
+ // Legacy apps do not know that they have to retry access to a
+ // resource due to changes in runtime permissions (app ops in this
+ // case). Therefore, we restart them on app op change, so they
+ // can pick up the change.
+ mActivityManager.killUid(uid, KILL_REASON_APP_OP_CHANGE);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public boolean revokeRuntimePermissions(boolean fixedByTheUser) {
+ final boolean isSharedUser = mPackageInfo.sharedUserId != null;
+ final int uid = mPackageInfo.applicationInfo.uid;
+
+ // We toggle permissions only to apps that support runtime
+ // permissions, otherwise we toggle the app op corresponding
+ // to the permission if the permission is granted to the app.
+ for (Permission permission : mPermissions.values()) {
+ if (mAppSupportsRuntimePermissions) {
+ // Revoke the permission if needed.
+ if (permission.isGranted()) {
+ permission.setGranted(false);
+ mPackageManager.revokeRuntimePermission(mPackageInfo.packageName,
+ permission.getName(), mUserHandle);
+ }
+
+ // Update the permission flags.
+ if (fixedByTheUser) {
+ // Take a note that the user fixed the permission.
+ if (permission.isUserSet() || !permission.isUserFixed()) {
+ permission.setUserSet(false);
+ permission.setUserFixed(true);
+ mPackageManager.updatePermissionFlags(permission.getName(),
+ mPackageInfo.packageName,
+ PackageManager.FLAG_PERMISSION_USER_SET
+ | PackageManager.FLAG_PERMISSION_USER_FIXED,
+ PackageManager.FLAG_PERMISSION_USER_FIXED,
+ mUserHandle);
+ }
+ } else {
+ if (!permission.isUserSet()) {
+ permission.setUserSet(true);
+ // Take a note that the user already chose once.
+ mPackageManager.updatePermissionFlags(permission.getName(),
+ mPackageInfo.packageName,
+ PackageManager.FLAG_PERMISSION_USER_SET,
+ PackageManager.FLAG_PERMISSION_USER_SET,
+ mUserHandle);
+ }
+ }
+
+ // Disable the permission app op.
+ if (permission.hasAppOp() && permission.isAppOpAllowed()) {
+ permission.setAppOpAllowed(false);
+ mAppOps.setMode(permission.getAppOp(), android.os.Process.myUid(),
+ mPackageInfo.packageName, AppOpsManager.MODE_IGNORED);
+ }
+ } else {
+ // Legacy apps cannot have a non-granted permission but just in case.
+ // Also if the permission has no corresponding app op, then it is a
+ // third-party one and we do not offer toggling of such permissions.
+ if (!permission.isGranted() || !permission.hasAppOp()) {
+ continue;
+ }
+
+ if (permission.isAppOpAllowed()) {
+ permission.setAppOpAllowed(false);
+ // It this is a shared user we want to enable the app op for all
+ // packages the the shared user to match the behavior of this
+ // shared user having a runtime permission.
+ if (isSharedUser) {
+ String[] packageNames = mPackageManager.getPackagesForUid(uid);
+ for (String packageName : packageNames) {
+ // Disable the app op.
+ mAppOps.setMode(permission.getAppOp(), uid,
+ packageName, AppOpsManager.MODE_IGNORED);
+ }
+ } else {
+ // Disable the app op.
+ mAppOps.setMode(permission.getAppOp(), uid,
+ mPackageInfo.packageName, AppOpsManager.MODE_IGNORED);
+ }
+
+ // Mark that the permission should not be granted on upgrade
+ // when the app begins supporting runtime permissions.
+ if (!permission.shouldRevokeOnUpgrade()) {
+ permission.setRevokeOnUpgrade(true);
+ mPackageManager.updatePermissionFlags(permission.getName(),
+ mPackageInfo.packageName,
+ PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE,
+ PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE,
+ mUserHandle);
+ }
+
+ // Disabling an app op may put the app in a situation in which it
+ // has a handle to state it shouldn't have, so we have to kill the
+ // app. This matches the revoke runtime permission behavior.
+ mActivityManager.killUid(uid, KILL_REASON_APP_OP_CHANGE);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public List<Permission> getPermissions() {
+ return new ArrayList<>(mPermissions.values());
+ }
+
+ public int getFlags() {
+ int flags = 0;
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ Permission permission = mPermissions.valueAt(i);
+ flags |= permission.getFlags();
+ }
+ return flags;
+ }
+
+ public boolean isUserFixed() {
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ Permission permission = mPermissions.valueAt(i);
+ if (!permission.isUserFixed()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean isPolicyFixed() {
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ Permission permission = mPermissions.valueAt(i);
+ if (permission.isPolicyFixed()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean isUserSet() {
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ Permission permission = mPermissions.valueAt(i);
+ if (!permission.isUserSet()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean isSystemFixed() {
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ Permission permission = mPermissions.valueAt(i);
+ if (permission.isSystemFixed()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public int compareTo(AppPermissionGroup another) {
+ final int result = mLabel.toString().compareTo(another.mLabel.toString());
+ if (result == 0) {
+ // Unbadged before badged.
+ return mPackageInfo.applicationInfo.uid
+ - another.mPackageInfo.applicationInfo.uid;
+ }
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj == null) {
+ return false;
+ }
+
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+
+ AppPermissionGroup other = (AppPermissionGroup) obj;
+
+ if (mName == null) {
+ if (other.mName != null) {
+ return false;
+ }
+ } else if (!mName.equals(other.mName)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return mName != null ? mName.hashCode() : 0;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append(getClass().getSimpleName());
+ builder.append("{name=").append(mName);
+ if (!mPermissions.isEmpty()) {
+ builder.append(", <has permissions>}");
+ } else {
+ builder.append('}');
+ }
+ return builder.toString();
+ }
+
+ private void addPermission(Permission permission) {
+ mPermissions.put(permission.getName(), permission);
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/model/AppPermissions.java b/src/com/android/packageinstaller/permission/model/AppPermissions.java
index 8258126a..17014774 100644
--- a/src/com/android/packageinstaller/permission/model/AppPermissions.java
+++ b/src/com/android/packageinstaller/permission/model/AppPermissions.java
@@ -28,7 +28,7 @@ import java.util.Collections;
import java.util.List;
public final class AppPermissions {
- private final ArrayMap<String, PermissionGroup> mGroups = new ArrayMap<>();
+ private final ArrayMap<String, AppPermissionGroup> mGroups = new ArrayMap<>();
private final Context mContext;
@@ -63,11 +63,11 @@ public final class AppPermissions {
return mAppLabel;
}
- public PermissionGroup getPermissionGroup(String name) {
+ public AppPermissionGroup getPermissionGroup(String name) {
return mGroups.get(name);
}
- public List<PermissionGroup> getPermissionGroups() {
+ public List<AppPermissionGroup> getPermissionGroups() {
return new ArrayList<>(mGroups.values());
}
@@ -84,7 +84,7 @@ public final class AppPermissions {
}
private void loadPermissionGroups() {
- List<PermissionGroup> groups = new ArrayList<>();
+ List<AppPermissionGroup> groups = new ArrayList<>();
if (mPackageInfo.requestedPermissions == null) {
return;
@@ -97,7 +97,7 @@ public final class AppPermissions {
continue;
}
- PermissionGroup group = PermissionGroup.create(mContext,
+ AppPermissionGroup group = AppPermissionGroup.create(mContext,
mPackageInfo, requestedPerm);
if (group == null) {
continue;
@@ -109,7 +109,7 @@ public final class AppPermissions {
if (!ArrayUtils.isEmpty(mFilterPermissions)) {
final int groupCount = groups.size();
for (int i = groupCount - 1; i >= 0; i--) {
- PermissionGroup group = groups.get(i);
+ AppPermissionGroup group = groups.get(i);
boolean groupHasPermission = false;
for (String filterPerm : mFilterPermissions) {
if (group.hasPermission(filterPerm)) {
@@ -126,14 +126,14 @@ public final class AppPermissions {
Collections.sort(groups);
mGroups.clear();
- for (PermissionGroup group : groups) {
+ for (AppPermissionGroup group : groups) {
mGroups.put(group.getName(), group);
}
}
private static boolean hasGroupForPermission(String permission,
- List<PermissionGroup> groups) {
- for (PermissionGroup group : groups) {
+ List<AppPermissionGroup> groups) {
+ for (AppPermissionGroup group : groups) {
if (group.hasPermission(permission)) {
return true;
}
diff --git a/src/com/android/packageinstaller/permission/model/PermissionApps.java b/src/com/android/packageinstaller/permission/model/PermissionApps.java
index 10ec9596..7191381d 100644
--- a/src/com/android/packageinstaller/permission/model/PermissionApps.java
+++ b/src/com/android/packageinstaller/permission/model/PermissionApps.java
@@ -107,14 +107,14 @@ public class PermissionApps {
public static class PermissionApp implements Comparable<PermissionApp> {
private final String mPackageName;
- private final PermissionGroup mPermissionGroup;
+ private final AppPermissionGroup mAppPermissionGroup;
private final String mLabel;
private final Drawable mIcon;
- public PermissionApp(String packageName, PermissionGroup permissionGroup,
+ public PermissionApp(String packageName, AppPermissionGroup appPermissionGroup,
String label, Drawable icon) {
mPackageName = packageName;
- mPermissionGroup = permissionGroup;
+ mAppPermissionGroup = appPermissionGroup;
mLabel = label;
mIcon = icon;
}
@@ -132,39 +132,39 @@ public class PermissionApps {
}
public boolean areRuntimePermissionsGranted() {
- return mPermissionGroup.areRuntimePermissionsGranted();
+ return mAppPermissionGroup.areRuntimePermissionsGranted();
}
public void grantRuntimePermissions() {
- mPermissionGroup.grantRuntimePermissions(false);
+ mAppPermissionGroup.grantRuntimePermissions(false);
}
public void revokeRuntimePermissions() {
- mPermissionGroup.revokeRuntimePermissions(false);
+ mAppPermissionGroup.revokeRuntimePermissions(false);
}
public boolean isPolicyFixed() {
- return mPermissionGroup.isPolicyFixed();
+ return mAppPermissionGroup.isPolicyFixed();
}
public boolean isSystemFixed() {
- return mPermissionGroup.isSystemFixed();
+ return mAppPermissionGroup.isSystemFixed();
}
public boolean hasRuntimePermissions() {
- return mPermissionGroup.hasRuntimePermission();
+ return mAppPermissionGroup.hasRuntimePermission();
}
public boolean hasAppOpPermissions() {
- return mPermissionGroup.hasAppOpPermission();
+ return mAppPermissionGroup.hasAppOpPermission();
}
public String getPackageName() {
return mPackageName;
}
- public PermissionGroup getPermissionGroup() {
- return mPermissionGroup;
+ public AppPermissionGroup getPermissionGroup() {
+ return mAppPermissionGroup;
}
@Override
@@ -178,7 +178,7 @@ public class PermissionApps {
}
private int getUid() {
- return mPermissionGroup.getApp().applicationInfo.uid;
+ return mAppPermissionGroup.getApp().applicationInfo.uid;
}
}
@@ -224,7 +224,7 @@ public class PermissionApps {
continue;
}
- PermissionGroup group = PermissionGroup.create(mContext,
+ AppPermissionGroup group = AppPermissionGroup.create(mContext,
app, groupInfo, groupPermInfos);
PermissionApp permApp = new PermissionApp(app.packageName,
diff --git a/src/com/android/packageinstaller/permission/model/PermissionGroup.java b/src/com/android/packageinstaller/permission/model/PermissionGroup.java
index 901f1a4e..8a602b44 100644
--- a/src/com/android/packageinstaller/permission/model/PermissionGroup.java
+++ b/src/com/android/packageinstaller/permission/model/PermissionGroup.java
@@ -16,466 +16,41 @@
package com.android.packageinstaller.permission.model;
-import android.app.ActivityManager;
-import android.app.AppOpsManager;
-import android.content.Context;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageItemInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PermissionGroupInfo;
-import android.content.pm.PermissionInfo;
-import android.os.Build;
-import android.os.UserHandle;
-import android.util.ArrayMap;
-
-import java.util.ArrayList;
-import java.util.List;
+import android.graphics.drawable.Drawable;
public final class PermissionGroup implements Comparable<PermissionGroup> {
- private static final String PLATFORM_PACKAGE_NAME = "android";
-
- private static final String KILL_REASON_APP_OP_CHANGE = "Permission related app op changed";
-
- private final Context mContext;
- private final UserHandle mUserHandle;
- private final PackageManager mPackageManager;
- private final AppOpsManager mAppOps;
- private final ActivityManager mActivityManager;
-
- private final PackageInfo mPackageInfo;
private final String mName;
+ private final String mDeclaringPackage;
private final CharSequence mLabel;
- private final ArrayMap<String, Permission> mPermissions = new ArrayMap<>();
- private final String mIconPkg;
- private final int mIconResId;
-
- private final boolean mAppSupportsRuntimePermissions;
-
- public static PermissionGroup create(Context context, PackageInfo packageInfo,
- String permissionName) {
- PermissionInfo permissionInfo;
- try {
- permissionInfo = context.getPackageManager().getPermissionInfo(permissionName, 0);
- } catch (PackageManager.NameNotFoundException e) {
- return null;
- }
-
- if (permissionInfo.protectionLevel != PermissionInfo.PROTECTION_DANGEROUS) {
- return null;
- }
-
- PackageItemInfo groupInfo = permissionInfo;
- if (permissionInfo.group != null) {
- try {
- groupInfo = context.getPackageManager().getPermissionGroupInfo(
- permissionInfo.group, 0);
- } catch (PackageManager.NameNotFoundException e) {
- /* ignore */
- }
- }
-
- List<PermissionInfo> permissionInfos = null;
- if (groupInfo instanceof PermissionGroupInfo) {
- try {
- permissionInfos = context.getPackageManager().queryPermissionsByGroup(
- groupInfo.name, 0);
- } catch (PackageManager.NameNotFoundException e) {
- /* ignore */
- }
- }
-
- return create(context, packageInfo, groupInfo, permissionInfos);
-
- }
-
- public static PermissionGroup create(Context context, PackageInfo packageInfo,
- PackageItemInfo groupInfo, List<PermissionInfo> permissionInfos) {
-
- PermissionGroup group = new PermissionGroup(context, packageInfo, groupInfo.name,
- groupInfo.loadLabel(context.getPackageManager()), groupInfo.packageName,
- groupInfo.icon);
-
- if (groupInfo instanceof PermissionInfo) {
- permissionInfos = new ArrayList<>();
- permissionInfos.add((PermissionInfo) groupInfo);
- }
-
- if (permissionInfos == null || permissionInfos.isEmpty()) {
- return null;
- }
-
- final int permissionCount = packageInfo.requestedPermissions.length;
- for (int i = 0; i < permissionCount; i++) {
- String requestedPermission = packageInfo.requestedPermissions[i];
-
- PermissionInfo requestedPermissionInfo = null;
-
- for (PermissionInfo permissionInfo : permissionInfos) {
- if (requestedPermission.equals(permissionInfo.name)) {
- requestedPermissionInfo = permissionInfo;
- break;
- }
- }
-
- if (requestedPermissionInfo == null) {
- continue;
- }
-
- // Collect only runtime permissions.
- if (requestedPermissionInfo.protectionLevel != PermissionInfo.PROTECTION_DANGEROUS) {
- continue;
- }
-
- // Don't allow toggle of non platform defined permissions for legacy apps via app ops.
- if (packageInfo.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1
- && !PLATFORM_PACKAGE_NAME.equals(requestedPermissionInfo.packageName)) {
- continue;
- }
-
- final boolean granted = (packageInfo.requestedPermissionsFlags[i]
- & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0;
-
- final int appOp = PLATFORM_PACKAGE_NAME.equals(requestedPermissionInfo.packageName)
- ? AppOpsManager.permissionToOpCode(requestedPermissionInfo.name)
- : AppOpsManager.OP_NONE;
-
- final boolean appOpAllowed = appOp != AppOpsManager.OP_NONE
- && context.getSystemService(AppOpsManager.class).checkOp(appOp,
- packageInfo.applicationInfo.uid, packageInfo.packageName)
- == AppOpsManager.MODE_ALLOWED;
+ private final Drawable mIcon;
- final int flags = context.getPackageManager().getPermissionFlags(
- requestedPermission, packageInfo.packageName,
- new UserHandle(context.getUserId()));
-
- Permission permission = new Permission(requestedPermission, granted,
- appOp, appOpAllowed, flags);
- group.addPermission(permission);
- }
-
- return group;
- }
-
- private PermissionGroup(Context context, PackageInfo packageInfo, String name,
- CharSequence label, String iconPkg, int iconResId) {
- mContext = context;
- mUserHandle = new UserHandle(mContext.getUserId());
- mPackageManager = mContext.getPackageManager();
- mPackageInfo = packageInfo;
- mAppSupportsRuntimePermissions = packageInfo.applicationInfo
- .targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1;
- mAppOps = context.getSystemService(AppOpsManager.class);
- mActivityManager = context.getSystemService(ActivityManager.class);
+ PermissionGroup(String name, String declaringPackage,
+ CharSequence label, Drawable icon) {
+ mDeclaringPackage = declaringPackage;
mName = name;
mLabel = label;
- mIconPkg = iconPkg;
- mIconResId = iconResId != 0 ? iconResId
- : com.android.internal.R.drawable.ic_perm_device_info;
- }
-
- public boolean hasRuntimePermission() {
- return mAppSupportsRuntimePermissions;
- }
-
- public boolean hasAppOpPermission() {
- final int permissionCount = mPermissions.size();
- for (int i = 0; i < permissionCount; i++) {
- Permission permission = mPermissions.valueAt(i);
- if (permission.getAppOp() != AppOpsManager.OP_NONE) {
- return true;
- }
- }
- return false;
- }
-
- public PackageInfo getApp() {
- return mPackageInfo;
+ mIcon = icon;
}
public String getName() {
return mName;
}
- public String getIconPkg() {
- return mIconPkg;
- }
-
- public int getIconResId() {
- return mIconResId;
+ public String getDeclaringPackage() {
+ return mDeclaringPackage;
}
public CharSequence getLabel() {
return mLabel;
}
- public boolean hasPermission(String permission) {
- return mPermissions.get(permission) != null;
- }
-
- public boolean areRuntimePermissionsGranted() {
- final int permissionCount = mPermissions.size();
- for (int i = 0; i < permissionCount; i++) {
- Permission permission = mPermissions.valueAt(i);
- if (mAppSupportsRuntimePermissions) {
- if (!permission.isGranted()) {
- return false;
- }
- } else if (permission.isGranted() && permission.getAppOp()
- != AppOpsManager.OP_NONE && !permission.isAppOpAllowed()) {
- return false;
- }
- }
- return true;
- }
-
- public boolean grantRuntimePermissions(boolean fixedByTheUser) {
- final boolean isSharedUser = mPackageInfo.sharedUserId != null;
- final int uid = mPackageInfo.applicationInfo.uid;
-
- // We toggle permissions only to apps that support runtime
- // permissions, otherwise we toggle the app op corresponding
- // to the permission if the permission is granted to the app.
- for (Permission permission : mPermissions.values()) {
- if (mAppSupportsRuntimePermissions) {
- // Grant the permission if needed.
- if (!permission.isGranted()) {
- permission.setGranted(true);
- mPackageManager.grantRuntimePermission(mPackageInfo.packageName,
- permission.getName(), new UserHandle(mContext.getUserId()));
- }
-
- // Update the permission flags.
- if (!fixedByTheUser) {
- // Now the apps can ask for the permission as the user
- // no longer has it fixed in a denied state.
- if (permission.isUserFixed() || !permission.isUserSet()) {
- permission.setUserFixed(false);
- permission.setUserSet(true);
- mPackageManager.updatePermissionFlags(permission.getName(),
- mPackageInfo.packageName,
- PackageManager.FLAG_PERMISSION_USER_FIXED
- | PackageManager.FLAG_PERMISSION_USER_SET,
- PackageManager.FLAG_PERMISSION_USER_SET,
- mUserHandle);
- }
- }
-
- // Enable the permission app op.
- if (permission.hasAppOp() && !permission.isAppOpAllowed()) {
- permission.setAppOpAllowed(true);
- mAppOps.setMode(permission.getAppOp(), android.os.Process.myUid(),
- mPackageInfo.packageName, AppOpsManager.MODE_ALLOWED);
- }
- } else {
- // Legacy apps cannot have a not granted permission but just in case.
- // Also if the permissions has no corresponding app op, then it is a
- // third-party one and we do not offer toggling of such permissions.
- if (!permission.isGranted() || !permission.hasAppOp()) {
- continue;
- }
-
- if (!permission.isAppOpAllowed()) {
- permission.setAppOpAllowed(true);
- // It this is a shared user we want to enable the app op for all
- // packages in the shared user to match the behavior of this
- // shared user having a runtime permission.
- if (isSharedUser) {
- // Enable the app op.
- String[] packageNames = mPackageManager.getPackagesForUid(uid);
- for (String packageName : packageNames) {
- mAppOps.setMode(permission.getAppOp(), uid, packageName,
- AppOpsManager.MODE_ALLOWED);
- }
- } else {
- // Enable the app op.
- mAppOps.setMode(permission.getAppOp(), uid, mPackageInfo.packageName,
- AppOpsManager.MODE_ALLOWED);
- }
-
- // Mark that the permission should not be be granted on upgrade
- // when the app begins supporting runtime permissions.
- if (permission.shouldRevokeOnUpgrade()) {
- permission.setRevokeOnUpgrade(false);
- mPackageManager.updatePermissionFlags(permission.getName(),
- mPackageInfo.packageName,
- PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE,
- 0, mUserHandle);
- }
-
- // Legacy apps do not know that they have to retry access to a
- // resource due to changes in runtime permissions (app ops in this
- // case). Therefore, we restart them on app op change, so they
- // can pick up the change.
- mActivityManager.killUid(uid, KILL_REASON_APP_OP_CHANGE);
- }
- }
- }
-
- return true;
- }
-
- public boolean revokeRuntimePermissions(boolean fixedByTheUser) {
- final boolean isSharedUser = mPackageInfo.sharedUserId != null;
- final int uid = mPackageInfo.applicationInfo.uid;
-
- // We toggle permissions only to apps that support runtime
- // permissions, otherwise we toggle the app op corresponding
- // to the permission if the permission is granted to the app.
- for (Permission permission : mPermissions.values()) {
- if (mAppSupportsRuntimePermissions) {
- // Revoke the permission if needed.
- if (permission.isGranted()) {
- permission.setGranted(false);
- mPackageManager.revokeRuntimePermission(mPackageInfo.packageName,
- permission.getName(), mUserHandle);
- }
-
- // Update the permission flags.
- if (fixedByTheUser) {
- // Take a note that the user fixed the permission.
- if (permission.isUserSet() || !permission.isUserFixed()) {
- permission.setUserSet(false);
- permission.setUserFixed(true);
- mPackageManager.updatePermissionFlags(permission.getName(),
- mPackageInfo.packageName,
- PackageManager.FLAG_PERMISSION_USER_SET
- | PackageManager.FLAG_PERMISSION_USER_FIXED,
- PackageManager.FLAG_PERMISSION_USER_FIXED,
- mUserHandle);
- }
- } else {
- if (!permission.isUserSet()) {
- permission.setUserSet(true);
- // Take a note that the user already chose once.
- mPackageManager.updatePermissionFlags(permission.getName(),
- mPackageInfo.packageName,
- PackageManager.FLAG_PERMISSION_USER_SET,
- PackageManager.FLAG_PERMISSION_USER_SET,
- mUserHandle);
- }
- }
-
- // Disable the permission app op.
- if (permission.hasAppOp() && permission.isAppOpAllowed()) {
- permission.setAppOpAllowed(false);
- mAppOps.setMode(permission.getAppOp(), android.os.Process.myUid(),
- mPackageInfo.packageName, AppOpsManager.MODE_IGNORED);
- }
- } else {
- // Legacy apps cannot have a non-granted permission but just in case.
- // Also if the permission has no corresponding app op, then it is a
- // third-party one and we do not offer toggling of such permissions.
- if (!permission.isGranted() || !permission.hasAppOp()) {
- continue;
- }
-
- if (permission.isAppOpAllowed()) {
- permission.setAppOpAllowed(false);
- // It this is a shared user we want to enable the app op for all
- // packages the the shared user to match the behavior of this
- // shared user having a runtime permission.
- if (isSharedUser) {
- String[] packageNames = mPackageManager.getPackagesForUid(uid);
- for (String packageName : packageNames) {
- // Disable the app op.
- mAppOps.setMode(permission.getAppOp(), uid,
- packageName, AppOpsManager.MODE_IGNORED);
- }
- } else {
- // Disable the app op.
- mAppOps.setMode(permission.getAppOp(), uid,
- mPackageInfo.packageName, AppOpsManager.MODE_IGNORED);
- }
-
- // Mark that the permission should not be granted on upgrade
- // when the app begins supporting runtime permissions.
- if (!permission.shouldRevokeOnUpgrade()) {
- permission.setRevokeOnUpgrade(true);
- mPackageManager.updatePermissionFlags(permission.getName(),
- mPackageInfo.packageName,
- PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE,
- PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE,
- mUserHandle);
- }
-
- // Disabling an app op may put the app in a situation in which it
- // has a handle to state it shouldn't have, so we have to kill the
- // app. This matches the revoke runtime permission behavior.
- mActivityManager.killUid(uid, KILL_REASON_APP_OP_CHANGE);
- }
- }
- }
-
- return true;
- }
-
- public List<Permission> getPermissions() {
- return new ArrayList<>(mPermissions.values());
- }
-
- public int getFlags() {
- int flags = 0;
- final int permissionCount = mPermissions.size();
- for (int i = 0; i < permissionCount; i++) {
- Permission permission = mPermissions.valueAt(i);
- flags |= permission.getFlags();
- }
- return flags;
- }
-
- public boolean isUserFixed() {
- final int permissionCount = mPermissions.size();
- for (int i = 0; i < permissionCount; i++) {
- Permission permission = mPermissions.valueAt(i);
- if (!permission.isUserFixed()) {
- return false;
- }
- }
- return true;
- }
-
- public boolean isPolicyFixed() {
- final int permissionCount = mPermissions.size();
- for (int i = 0; i < permissionCount; i++) {
- Permission permission = mPermissions.valueAt(i);
- if (permission.isPolicyFixed()) {
- return true;
- }
- }
- return false;
- }
-
- public boolean isUserSet() {
- final int permissionCount = mPermissions.size();
- for (int i = 0; i < permissionCount; i++) {
- Permission permission = mPermissions.valueAt(i);
- if (!permission.isUserSet()) {
- return false;
- }
- }
- return true;
- }
-
- public boolean isSystemFixed() {
- final int permissionCount = mPermissions.size();
- for (int i = 0; i < permissionCount; i++) {
- Permission permission = mPermissions.valueAt(i);
- if (permission.isSystemFixed()) {
- return true;
- }
- }
- return false;
+ public Drawable getIcon() {
+ return mIcon;
}
@Override
public int compareTo(PermissionGroup another) {
- final int result = mLabel.toString().compareTo(another.mLabel.toString());
- if (result == 0) {
- // Unbadged before badged.
- return mPackageInfo.applicationInfo.uid
- - another.mPackageInfo.applicationInfo.uid;
- }
- return result;
+ return mLabel.toString().compareTo(another.mLabel.toString());
}
@Override
@@ -509,22 +84,4 @@ public final class PermissionGroup implements Comparable<PermissionGroup> {
public int hashCode() {
return mName != null ? mName.hashCode() : 0;
}
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder();
- builder.append(getClass().getSimpleName());
- builder.append("{name=").append(mName);
- if (!mPermissions.isEmpty()) {
- builder.append(", <has permissions>}");
- } else {
- builder.append('}');
- }
- return builder.toString();
- }
-
- private void addPermission(Permission permission) {
- mPermissions.put(permission.getName(), permission);
- }
}
-
diff --git a/src/com/android/packageinstaller/permission/model/PermissionGroups.java b/src/com/android/packageinstaller/permission/model/PermissionGroups.java
new file mode 100644
index 00000000..62477b88
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/model/PermissionGroups.java
@@ -0,0 +1,222 @@
+/*
+ * 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.packageinstaller.permission.model;
+
+import android.app.LoaderManager;
+import android.app.LoaderManager.LoaderCallbacks;
+import android.content.AsyncTaskLoader;
+import android.content.Context;
+import android.content.Loader;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageItemInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionGroupInfo;
+import android.content.pm.PermissionInfo;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.util.ArraySet;
+
+import com.android.packageinstaller.R;
+import com.android.packageinstaller.permission.utils.Utils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+public final class PermissionGroups implements LoaderCallbacks<List<PermissionGroup>> {
+ private final ArrayList<PermissionGroup> mGroups = new ArrayList<>();
+ private final Context mContext;
+ private final LoaderManager mLoaderManager;
+ private final PermissionsGroupsChangeCallback mCallback;
+
+ public interface PermissionsGroupsChangeCallback {
+ public void onPermissionGroupsChanged();
+ }
+
+ public PermissionGroups(Context context, LoaderManager loaderManager,
+ PermissionsGroupsChangeCallback callback) {
+ mContext = context;
+ mLoaderManager = loaderManager;
+ mCallback = callback;
+ }
+
+ @Override
+ public Loader<List<PermissionGroup>> onCreateLoader(int id, Bundle args) {
+ return new PermissionsLoader(mContext);
+ }
+
+ @Override
+ public void onLoadFinished(Loader<List<PermissionGroup>> loader,
+ List<PermissionGroup> groups) {
+ if (mGroups.equals(groups)) {
+ return;
+ }
+ mGroups.clear();
+ mGroups.addAll(groups);
+ mCallback.onPermissionGroupsChanged();
+ }
+
+ @Override
+ public void onLoaderReset(Loader<List<PermissionGroup>> loader) {
+ mGroups.clear();
+ mCallback.onPermissionGroupsChanged();
+ }
+
+ public void refresh() {
+ mLoaderManager.restartLoader(0, null, this);
+ mLoaderManager.getLoader(0).forceLoad();
+ }
+
+ public List<PermissionGroup> getGroups() {
+ return mGroups;
+ }
+
+ public PermissionGroup getGroup(String name) {
+ for (PermissionGroup group : mGroups) {
+ if (group.getName().equals(name)) {
+ return group;
+ }
+ }
+ return null;
+ }
+
+ private static final class PermissionsLoader extends AsyncTaskLoader<List<PermissionGroup>> {
+
+ public PermissionsLoader(Context context) {
+ super(context);
+ }
+
+ @Override
+ public List<PermissionGroup> loadInBackground() {
+ List<PermissionGroup> groups = new ArrayList<>();
+ Set<String> seenPermissions = new ArraySet<>();
+
+
+ PackageManager packageManager = getContext().getPackageManager();
+ List<PermissionGroupInfo> groupInfos = packageManager.getAllPermissionGroups(0);
+
+ for (PermissionGroupInfo groupInfo : groupInfos) {
+ // Mare sure we respond to cancellation.
+ if (isLoadInBackgroundCanceled()) {
+ return Collections.emptyList();
+ }
+
+ // Get the permissions in this group.
+ final List<PermissionInfo> groupPermissions;
+ try {
+ groupPermissions = packageManager.queryPermissionsByGroup(groupInfo.name, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ continue;
+ }
+
+ boolean hasRuntimePermissions = false;
+
+ // Cache seen permissions and see if group has runtime permissions.
+ for (PermissionInfo groupPermission : groupPermissions) {
+ seenPermissions.add(groupPermission.name);
+ if (groupPermission.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS) {
+ hasRuntimePermissions = true;
+ }
+ }
+
+ // No runtime permissions - not interesting for us.
+ if (!hasRuntimePermissions) {
+ continue;
+ }
+
+ CharSequence label = loadItemInfoLabel(groupInfo);
+ Drawable icon = loadItemInfoIcon(groupInfo);
+
+ // Create the group and add to the list.
+ PermissionGroup group = new PermissionGroup(groupInfo.name,
+ groupInfo.packageName, label, icon);
+ groups.add(group);
+ }
+
+
+ // Make sure we add groups for lone runtime permissions.
+ List<PackageInfo> installedPackages = getContext().getPackageManager()
+ .getInstalledPackages(PackageManager.GET_PERMISSIONS);
+
+
+ // We will filter out permissions that no package requests.
+ Set<String> requestedPermissions = new ArraySet<>();
+ for (PackageInfo installedPackage : installedPackages) {
+ if (installedPackage.requestedPermissions == null) {
+ break;
+ }
+ for (String requestedPermission : installedPackage.requestedPermissions) {
+ requestedPermissions.add(requestedPermission);
+ }
+ }
+
+ for (PackageInfo installedPackage : installedPackages) {
+ if (installedPackage.permissions == null) {
+ continue;
+ }
+
+ for (PermissionInfo permissionInfo : installedPackage.permissions) {
+ // If we have handled this permission, no more work to do.
+ if (!seenPermissions.add(permissionInfo.name)) {
+ continue;
+ }
+
+ // We care only about runtime permissions.
+ if (permissionInfo.protectionLevel != PermissionInfo.PROTECTION_DANGEROUS) {
+ continue;
+ }
+
+ // If no app uses this permission,
+ if (!requestedPermissions.contains(permissionInfo.name)) {
+ continue;
+ }
+
+ CharSequence label = loadItemInfoLabel(permissionInfo);
+ Drawable icon = loadItemInfoIcon(permissionInfo);
+
+ // Create the group and add to the list.
+ PermissionGroup group = new PermissionGroup(permissionInfo.name,
+ permissionInfo.packageName, label, icon);
+ groups.add(group);
+ }
+ }
+
+ Collections.sort(groups);
+ return groups;
+ }
+
+ private CharSequence loadItemInfoLabel(PackageItemInfo itemInfo) {
+ CharSequence label = itemInfo.loadLabel(getContext().getPackageManager());
+ if (label == null) {
+ label = itemInfo.name;
+ }
+ return label;
+ }
+
+ private Drawable loadItemInfoIcon(PackageItemInfo itemInfo) {
+ final Drawable icon;
+ if (itemInfo.icon > 0) {
+ icon = Utils.loadDrawable(getContext().getPackageManager(),
+ itemInfo.packageName, itemInfo.icon);
+ } else {
+ icon = getContext().getDrawable(R.drawable.ic_perm_device_info);
+ }
+ return icon;
+ }
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/ui/AppPermissionsFragment.java b/src/com/android/packageinstaller/permission/ui/AppPermissionsFragment.java
index e1dd85a6..79e66246 100644
--- a/src/com/android/packageinstaller/permission/ui/AppPermissionsFragment.java
+++ b/src/com/android/packageinstaller/permission/ui/AppPermissionsFragment.java
@@ -38,6 +38,8 @@ import android.preference.SwitchPreference;
import android.provider.Settings;
import android.util.Log;
import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
@@ -47,8 +49,8 @@ import android.widget.TextView;
import android.widget.Toast;
import com.android.packageinstaller.R;
+import com.android.packageinstaller.permission.model.AppPermissionGroup;
import com.android.packageinstaller.permission.model.AppPermissions;
-import com.android.packageinstaller.permission.model.PermissionGroup;
import com.android.packageinstaller.permission.utils.SafetyNetLogger;
import com.android.packageinstaller.permission.utils.Utils;
@@ -64,11 +66,12 @@ public final class AppPermissionsFragment extends SettingsWithHeader
private static final String EXTRA_HIDE_INFO_BUTTON = "hideInfoButton";
- private List<PermissionGroup> mToggledGroups;
+ private List<AppPermissionGroup> mToggledGroups;
private AppPermissions mAppPermissions;
private PreferenceScreen mExtraScreen;
private boolean mHasConfirmedRevoke;
+ private boolean mShowLegacyPermissions;
public static AppPermissionsFragment newInstance(String packageName) {
AppPermissionsFragment instance = new AppPermissionsFragment();
@@ -98,9 +101,16 @@ public final class AppPermissionsFragment extends SettingsWithHeader
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
- case android.R.id.home:
+ case android.R.id.home: {
getActivity().finish();
return true;
+ }
+
+ case R.id.toggle_legacy_permissions: {
+ mShowLegacyPermissions = !mShowLegacyPermissions;
+ updatePermissionsUi();
+ return true;
+ }
}
return super.onOptionsItemSelected(item);
}
@@ -124,6 +134,23 @@ public final class AppPermissionsFragment extends SettingsWithHeader
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
bindUi();
+ updatePermissionsUi();
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ inflater.inflate(R.menu.toggle_legacy_permissions, menu);
+ }
+
+ @Override
+ public void onPrepareOptionsMenu(Menu menu) {
+ MenuItem item = menu.findItem(R.id.toggle_legacy_permissions);
+ if (!mShowLegacyPermissions) {
+ item.setTitle(R.string.show_legacy_permissions);
+ } else {
+ item.setTitle(R.string.hide_legacy_permissions);
+ }
}
private void bindUi() {
@@ -162,7 +189,6 @@ public final class AppPermissionsFragment extends SettingsWithHeader
breadcrumbView.setText(label);
}
- PreferenceScreen screen = getPreferenceManager().createPreferenceScreen(activity);
mAppPermissions = new AppPermissions(activity, packageInfo, null, new Runnable() {
@Override
public void run() {
@@ -170,11 +196,26 @@ public final class AppPermissionsFragment extends SettingsWithHeader
}
});
+ PreferenceScreen screen = getPreferenceManager().createPreferenceScreen(activity);
+ setPreferenceScreen(screen);
+ }
+
+ private void updatePermissionsUi() {
+ final Activity activity = getActivity();
+
+ if (activity == null) {
+ return;
+ }
+
+ final PreferenceScreen screen = getPreferenceScreen();
+ screen.removeAll();
+ mExtraScreen = null;
+
final Preference extraPerms = new Preference(activity);
extraPerms.setIcon(R.drawable.ic_toc);
extraPerms.setTitle(R.string.additional_permissions);
- for (PermissionGroup group : mAppPermissions.getPermissionGroups()) {
+ for (AppPermissionGroup group : mAppPermissions.getPermissionGroups()) {
// We currently will not show permissions fixed by the system
// which is what the system does for system components.
if (group.isSystemFixed()) {
@@ -188,14 +229,20 @@ public final class AppPermissionsFragment extends SettingsWithHeader
continue;
}
+ // Show legacy permissions only if the user chose that.
+ if (!mShowLegacyPermissions && !Utils.isModernPermissionGroup(group.getName())) {
+ continue;
+ }
+
SwitchPreference preference = new SwitchPreference(activity);
preference.setOnPreferenceChangeListener(this);
preference.setKey(group.getName());
- preference.setIcon(Utils.loadDrawable(pm, group.getIconPkg(),
- group.getIconResId()));
+ preference.setIcon(Utils.loadDrawable(activity.getPackageManager(),
+ group.getIconPkg(), group.getIconResId()));
preference.setTitle(group.getLabel());
preference.setPersistent(false);
preference.setEnabled(!group.isPolicyFixed());
+
if (group.getIconPkg().equals(OS_PKG)) {
screen.addPreference(preference);
} else {
@@ -205,6 +252,7 @@ public final class AppPermissionsFragment extends SettingsWithHeader
mExtraScreen.addPreference(preference);
}
}
+
if (mExtraScreen != null) {
extraPerms.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
@@ -222,14 +270,12 @@ public final class AppPermissionsFragment extends SettingsWithHeader
mExtraScreen.getPreferenceCount()));
screen.addPreference(extraPerms);
}
-
- setPreferenceScreen(screen);
}
@Override
public boolean onPreferenceChange(final Preference preference, Object newValue) {
String groupName = preference.getKey();
- final PermissionGroup group = mAppPermissions.getPermissionGroup(groupName);
+ final AppPermissionGroup group = mAppPermissions.getPermissionGroup(groupName);
if (group == null) {
return false;
@@ -269,7 +315,7 @@ public final class AppPermissionsFragment extends SettingsWithHeader
logToggledGroups();
}
- private void addToggledGroup(PermissionGroup group) {
+ private void addToggledGroup(AppPermissionGroup group) {
if (mToggledGroups == null) {
mToggledGroups = new ArrayList<>();
}
@@ -304,7 +350,7 @@ public final class AppPermissionsFragment extends SettingsWithHeader
Preference preference = screen.getPreference(i);
if (preference instanceof SwitchPreference) {
SwitchPreference switchPref = (SwitchPreference) preference;
- PermissionGroup group = mAppPermissions
+ AppPermissionGroup group = mAppPermissions
.getPermissionGroup(switchPref.getKey());
if (group != null) {
switchPref.setChecked(group.areRuntimePermissionsGranted());
diff --git a/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java b/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java
index b406db18..6f824ea0 100644
--- a/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java
+++ b/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java
@@ -34,9 +34,9 @@ import android.util.Log;
import android.util.SparseArray;
import com.android.packageinstaller.R;
+import com.android.packageinstaller.permission.model.AppPermissionGroup;
import com.android.packageinstaller.permission.model.AppPermissions;
import com.android.packageinstaller.permission.model.Permission;
-import com.android.packageinstaller.permission.model.PermissionGroup;
import com.android.packageinstaller.permission.utils.SafetyNetLogger;
import java.util.ArrayList;
@@ -100,7 +100,7 @@ public class GrantPermissionsActivity extends Activity implements
}
});
- for (PermissionGroup group : mAppPermissions.getPermissionGroups()) {
+ for (AppPermissionGroup group : mAppPermissions.getPermissionGroups()) {
// We allow the user to choose only non-fixed permissions. A permission
// is fixed either by device policy or the user denying with prejudice.
if (!group.areRuntimePermissionsGranted() &&
@@ -201,7 +201,7 @@ public class GrantPermissionsActivity extends Activity implements
}
}
- private void updateGrantResults(PermissionGroup group) {
+ private void updateGrantResults(AppPermissionGroup group) {
for (Permission permission : group.getPermissions()) {
if (permission.isGranted()) {
final int index = ArrayUtils.getArrayIndex(
@@ -307,7 +307,7 @@ public class GrantPermissionsActivity extends Activity implements
}
final int groupCount = mRequestGrantPermissionGroups.size();
- List<PermissionGroup> groups = new ArrayList<>(groupCount);
+ List<AppPermissionGroup> groups = new ArrayList<>(groupCount);
for (int i = 0; i < groupCount; i++) {
groups.add(mRequestGrantPermissionGroups.valueAt(i).mGroup);
}
@@ -320,10 +320,10 @@ public class GrantPermissionsActivity extends Activity implements
public static final int STATE_ALLOWED = 1;
public static final int STATE_DENIED = 2;
- public final PermissionGroup mGroup;
+ public final AppPermissionGroup mGroup;
public int mState = STATE_UNKNOWN;
- public GroupState(PermissionGroup group) {
+ public GroupState(AppPermissionGroup group) {
mGroup = group;
}
}
diff --git a/src/com/android/packageinstaller/permission/ui/ManagePermissionsActivity.java b/src/com/android/packageinstaller/permission/ui/ManagePermissionsActivity.java
index ef117a9c..2fc1a02b 100644
--- a/src/com/android/packageinstaller/permission/ui/ManagePermissionsActivity.java
+++ b/src/com/android/packageinstaller/permission/ui/ManagePermissionsActivity.java
@@ -31,26 +31,37 @@ public final class ManagePermissionsActivity extends Activity {
Fragment fragment = null;
String action = getIntent().getAction();
- if (Intent.ACTION_MANAGE_APP_PERMISSIONS.equals(action)) {
- String packageName = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME);
- if (packageName == null) {
- Log.i(LOG_TAG, "Missing mandatory argument EXTRA_PACKAGE_NAME");
- finish();
- return;
- }
- fragment = AppPermissionsFragment.newInstance(packageName);
- } else if (Intent.ACTION_MANAGE_PERMISSION_APPS.equals(action)) {
- String permissionName = getIntent().getStringExtra(Intent.EXTRA_PERMISSION_NAME);
- if (permissionName == null) {
- Log.i(LOG_TAG, "Missing mandatory argument EXTRA_PERMISSION_NAME");
+
+ switch (action) {
+ case Intent.ACTION_MANAGE_PERMISSIONS: {
+ fragment = ManagePermissionsFragment.newInstance();
+ } break;
+
+ case Intent.ACTION_MANAGE_APP_PERMISSIONS: {
+ String packageName = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME);
+ if (packageName == null) {
+ Log.i(LOG_TAG, "Missing mandatory argument EXTRA_PACKAGE_NAME");
+ finish();
+ return;
+ }
+ fragment = AppPermissionsFragment.newInstance(packageName);
+ } break;
+
+ case Intent.ACTION_MANAGE_PERMISSION_APPS: {
+ String permissionName = getIntent().getStringExtra(Intent.EXTRA_PERMISSION_NAME);
+ if (permissionName == null) {
+ Log.i(LOG_TAG, "Missing mandatory argument EXTRA_PERMISSION_NAME");
+ finish();
+ return;
+ }
+ fragment = PermissionAppsFragment.newInstance(permissionName);
+ } break;
+
+ default: {
+ Log.w(LOG_TAG, "Unrecognized action " + action);
finish();
return;
}
- fragment = PermissionAppsFragment.newInstance(permissionName);
- } else {
- Log.w(LOG_TAG, "Unrecognized action " + action);
- finish();
- return;
}
getFragmentManager().beginTransaction().replace(android.R.id.content, fragment).commit();
diff --git a/src/com/android/packageinstaller/permission/ui/ManagePermissionsFragment.java b/src/com/android/packageinstaller/permission/ui/ManagePermissionsFragment.java
new file mode 100644
index 00000000..5158b5e8
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/ui/ManagePermissionsFragment.java
@@ -0,0 +1,216 @@
+/*
+ * 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.packageinstaller.permission.ui;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.app.FragmentTransaction;
+import android.content.ActivityNotFoundException;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceClickListener;
+import android.preference.PreferenceFragment;
+import android.preference.PreferenceScreen;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+
+import com.android.packageinstaller.R;
+import com.android.packageinstaller.permission.model.PermissionGroup;
+import com.android.packageinstaller.permission.model.PermissionGroups;
+import com.android.packageinstaller.permission.utils.Utils;
+
+import java.util.List;
+
+public final class ManagePermissionsFragment extends PreferenceFragment
+ implements PermissionGroups.PermissionsGroupsChangeCallback, OnPreferenceClickListener {
+ private static final String LOG_TAG = "ManagePermissionsFragment";
+
+ private static final String OS_PKG = "android";
+
+ private PermissionGroups mPermissions;
+
+ private PreferenceScreen mExtraScreen;
+
+ private boolean mShowLegacyPermissions;
+
+ public static ManagePermissionsFragment newInstance() {
+ return new ManagePermissionsFragment();
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setHasOptionsMenu(true);
+ final ActionBar ab = getActivity().getActionBar();
+ if (ab != null) {
+ ab.setDisplayHomeAsUpEnabled(true);
+ }
+ mPermissions = new PermissionGroups(getActivity(), getLoaderManager(), this);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mPermissions.refresh();
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ inflater.inflate(R.menu.toggle_legacy_permissions, menu);
+ }
+
+ @Override
+ public void onPrepareOptionsMenu(Menu menu) {
+ MenuItem item = menu.findItem(R.id.toggle_legacy_permissions);
+ if (!mShowLegacyPermissions) {
+ item.setTitle(R.string.show_legacy_permissions);
+ } else {
+ item.setTitle(R.string.hide_legacy_permissions);
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home: {
+ getActivity().finish();
+ return true;
+ }
+
+ case R.id.toggle_legacy_permissions: {
+ mShowLegacyPermissions = !mShowLegacyPermissions;
+ updatePermissionsUi();
+ return true;
+ }
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ String key = preference.getKey();
+
+ PermissionGroup group = mPermissions.getGroup(key);
+ if (group == null) {
+ return false;
+ }
+
+ Intent intent = new Intent(Intent.ACTION_MANAGE_PERMISSION_APPS)
+ .putExtra(Intent.EXTRA_PERMISSION_NAME, key);
+ try {
+ getActivity().startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Log.w(LOG_TAG, "No app to handle " + intent);
+ }
+
+ return true;
+ }
+
+ @Override
+ public void onPermissionGroupsChanged() {
+ updatePermissionsUi();
+ }
+
+ private void updatePermissionsUi() {
+ Activity activity = getActivity();
+
+ if (activity == null) {
+ return;
+ }
+
+ List<PermissionGroup> groups = mPermissions.getGroups();
+
+ PreferenceScreen screen = getPreferenceScreen();
+ if (screen == null) {
+ screen = getPreferenceManager().createPreferenceScreen(activity);
+ setPreferenceScreen(screen);
+ } else {
+ screen.removeAll();
+ if (mExtraScreen != null) {
+ mExtraScreen.removeAll();
+ }
+ }
+
+ for (PermissionGroup group : groups) {
+ // Show legacy permissions only if the user chose that.
+ if (!mShowLegacyPermissions && group.getDeclaringPackage().equals(OS_PKG)
+ && !Utils.isModernPermissionGroup(group.getName())) {
+ continue;
+ }
+
+ Preference preference = new Preference(activity);
+ preference.setOnPreferenceClickListener(this);
+ preference.setKey(group.getName());
+ preference.setIcon(group.getIcon());
+ preference.setTitle(group.getLabel());
+ preference.setPersistent(false);
+
+ if (group.getDeclaringPackage().equals(OS_PKG)) {
+ screen.addPreference(preference);
+ } else {
+ if (mExtraScreen == null) {
+ mExtraScreen = getPreferenceManager().createPreferenceScreen(activity);
+ }
+ mExtraScreen.addPreference(preference);
+ }
+ }
+
+ if (mExtraScreen != null && mExtraScreen.getPreferenceCount() > 0) {
+ Preference extraScreenPreference = new Preference(activity);
+ extraScreenPreference.setIcon(R.drawable.ic_toc);
+ extraScreenPreference.setTitle(R.string.additional_permissions);
+ extraScreenPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ AdditionalPermissionsFragment frag = new AdditionalPermissionsFragment();
+ frag.setTargetFragment(ManagePermissionsFragment.this, 0);
+ FragmentTransaction ft = getFragmentManager().beginTransaction();
+ ft.replace(android.R.id.content, frag);
+ ft.addToBackStack("AdditionalPerms");
+ ft.commit();
+ return true;
+ }
+ });
+ extraScreenPreference.setSummary(getString(R.string.additional_permissions_more,
+ mExtraScreen.getPreferenceCount()));
+ screen.addPreference(extraScreenPreference);
+ }
+ }
+
+ public static class AdditionalPermissionsFragment extends SettingsWithHeader {
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setPreferenceScreen(((ManagePermissionsFragment) getTargetFragment()).mExtraScreen);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ Resources resources = getResources();
+ Theme theme = getActivity().getTheme();
+ setHeader(resources.getDrawable(R.drawable.ic_toc, theme),
+ getString(R.string.additional_permissions), null);
+ }
+ }
+}
diff --git a/src/com/android/packageinstaller/permission/ui/PermissionAppsFragment.java b/src/com/android/packageinstaller/permission/ui/PermissionAppsFragment.java
index d1d7c87e..cbfcc528 100644
--- a/src/com/android/packageinstaller/permission/ui/PermissionAppsFragment.java
+++ b/src/com/android/packageinstaller/permission/ui/PermissionAppsFragment.java
@@ -37,10 +37,10 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.android.packageinstaller.R;
+import com.android.packageinstaller.permission.model.AppPermissionGroup;
import com.android.packageinstaller.permission.model.PermissionApps;
import com.android.packageinstaller.permission.model.PermissionApps.Callback;
import com.android.packageinstaller.permission.model.PermissionApps.PermissionApp;
-import com.android.packageinstaller.permission.model.PermissionGroup;
import com.android.packageinstaller.permission.utils.SafetyNetLogger;
import java.util.ArrayList;
@@ -59,7 +59,7 @@ public final class PermissionAppsFragment extends SettingsWithHeader implements
private PermissionApps mPermissionApps;
- private ArrayMap<String, PermissionGroup> mToggledGroups;
+ private ArrayMap<String, AppPermissionGroup> mToggledGroups;
private boolean mHasConfirmedRevoke;
@Override
@@ -136,6 +136,11 @@ public final class PermissionAppsFragment extends SettingsWithHeader implements
@Override
public void onPermissionsLoaded() {
Context context = getActivity();
+
+ if (context == null) {
+ return;
+ }
+
PreferenceScreen preferences = getPreferenceScreen();
if (preferences == null) {
preferences = getPreferenceManager().createPreferenceScreen(getActivity());
@@ -212,7 +217,7 @@ public final class PermissionAppsFragment extends SettingsWithHeader implements
logToggledGroups();
}
- private void addToggledGroup(String packageName, PermissionGroup group) {
+ private void addToggledGroup(String packageName, AppPermissionGroup group) {
if (mToggledGroups == null) {
mToggledGroups = new ArrayMap<>();
}
@@ -229,7 +234,7 @@ public final class PermissionAppsFragment extends SettingsWithHeader implements
final int groupCount = mToggledGroups.size();
for (int i = 0; i < groupCount; i++) {
String packageName = mToggledGroups.keyAt(i);
- List<PermissionGroup> groups = new ArrayList<>();
+ List<AppPermissionGroup> groups = new ArrayList<>();
groups.add(mToggledGroups.valueAt(i));
SafetyNetLogger.logPermissionsToggled(packageName, groups);
}
diff --git a/src/com/android/packageinstaller/permission/utils/SafetyNetLogger.java b/src/com/android/packageinstaller/permission/utils/SafetyNetLogger.java
index 0163b750..8280ba36 100644
--- a/src/com/android/packageinstaller/permission/utils/SafetyNetLogger.java
+++ b/src/com/android/packageinstaller/permission/utils/SafetyNetLogger.java
@@ -18,7 +18,7 @@ package com.android.packageinstaller.permission.utils;
import android.content.pm.PackageInfo;
import android.util.EventLog;
-import com.android.packageinstaller.permission.model.PermissionGroup;
+import com.android.packageinstaller.permission.model.AppPermissionGroup;
import java.util.List;
@@ -38,27 +38,27 @@ public final class SafetyNetLogger {
}
public static void logPermissionsRequested(PackageInfo packageInfo,
- List<PermissionGroup> groups) {
+ List<AppPermissionGroup> groups) {
EventLog.writeEvent(SNET_NET_EVENT_LOG_TAG, PERMISSIONS_REQUESTED,
packageInfo.applicationInfo.uid, buildChangedGroupForPackageMessage(
packageInfo.packageName, groups));
}
- public static void logPermissionsToggled(String packageName, List<PermissionGroup> groups) {
+ public static void logPermissionsToggled(String packageName, List<AppPermissionGroup> groups) {
EventLog.writeEvent(SNET_NET_EVENT_LOG_TAG, PERMISSIONS_TOGGLED,
android.os.Process.myUid(), buildChangedGroupForPackageMessage(
packageName, groups));
}
private static String buildChangedGroupForPackageMessage(String packageName,
- List<PermissionGroup> groups) {
+ List<AppPermissionGroup> groups) {
StringBuilder builder = new StringBuilder();
builder.append(packageName).append(':');
final int groupCount = groups.size();
for (int i = 0; i < groupCount; i++) {
- PermissionGroup group = groups.get(i);
+ AppPermissionGroup group = groups.get(i);
if (i > 0) {
builder.append(';');
}
diff --git a/src/com/android/packageinstaller/permission/utils/Utils.java b/src/com/android/packageinstaller/permission/utils/Utils.java
index 0dea8f34..7abb2627 100644
--- a/src/com/android/packageinstaller/permission/utils/Utils.java
+++ b/src/com/android/packageinstaller/permission/utils/Utils.java
@@ -16,6 +16,7 @@
package com.android.packageinstaller.permission.utils;
+import android.Manifest;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
@@ -36,4 +37,23 @@ public class Utils {
return null;
}
}
+
+ public static boolean isModernPermissionGroup(String name) {
+ switch (name) {
+ case Manifest.permission_group.CALENDAR:
+ case Manifest.permission_group.CAMERA:
+ case Manifest.permission_group.CONTACTS:
+ case Manifest.permission_group.LOCATION:
+ case Manifest.permission_group.SENSORS:
+ case Manifest.permission_group.SMS:
+ case Manifest.permission_group.PHONE:
+ case Manifest.permission_group.MICROPHONE: {
+ return true;
+ }
+
+ default: {
+ return false;
+ }
+ }
+ }
}