diff options
author | Jason Monk <jmonk@google.com> | 2015-03-26 08:30:50 -0400 |
---|---|---|
committer | Jason Monk <jmonk@google.com> | 2015-03-30 10:39:29 -0400 |
commit | 2f41aa7955e27a050155765803d3a5ae98782f26 (patch) | |
tree | 98a9e44dc8c33e9ce6df33f1bb833a76ac597c08 /src/com/android | |
parent | ec5a3373db706778d2bcde6700c270f33bf8f7f1 (diff) | |
download | packages_apps_Settings-2f41aa7955e27a050155765803d3a5ae98782f26.tar.gz packages_apps_Settings-2f41aa7955e27a050155765803d3a5ae98782f26.tar.bz2 packages_apps_Settings-2f41aa7955e27a050155765803d3a5ae98782f26.zip |
Add permissions screen to advanced apps
Add a screen that shows a list of permissions and how many apps
have been granted them, link to PackageInstaller for control of
the permissions.
Depends on I68cdbe53177f742daf396f4eb53761fd5cda2636
Change-Id: I183848ea89ea41a17eaf663441dc4ef963be99bf
Diffstat (limited to 'src/com/android')
3 files changed, 322 insertions, 1 deletions
diff --git a/src/com/android/settings/applications/AdvancedAppSettings.java b/src/com/android/settings/applications/AdvancedAppSettings.java index 28ac1d090..d5ab8dc01 100644 --- a/src/com/android/settings/applications/AdvancedAppSettings.java +++ b/src/com/android/settings/applications/AdvancedAppSettings.java @@ -26,6 +26,7 @@ import android.content.Context; import android.content.DialogInterface; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.net.NetworkPolicyManager; import android.os.AsyncTask; @@ -34,9 +35,11 @@ import android.os.Handler; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; +import android.os.UserManager; import android.preference.Preference; import android.preference.Preference.OnPreferenceClickListener; import android.util.Log; +import android.util.Pair; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -47,22 +50,25 @@ import com.android.settings.SettingsPreferenceFragment; import com.android.settings.applications.ApplicationsState.AppEntry; import com.android.settings.applications.ApplicationsState.Callbacks; import com.android.settings.applications.ApplicationsState.Session; +import com.android.settings.applications.PermissionsInfo.Callback; import java.util.ArrayList; import java.util.List; public class AdvancedAppSettings extends SettingsPreferenceFragment implements Callbacks, - DialogInterface.OnClickListener, DialogInterface.OnDismissListener { + DialogInterface.OnClickListener, DialogInterface.OnDismissListener, Callback { static final String TAG = "AdvancedAppSettings"; static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + private static final String KEY_APP_PERM = "manage_perms"; private static final String KEY_ALL_APPS = "all_apps"; private static final String KEY_RESET_ALL = "reset_all"; private static final String EXTRA_RESET_DIALOG = "resetDialog"; private ApplicationsState mApplicationsState; private Session mSession; + private Preference mAppPerms; private Preference mAllApps; private Preference mResetAll; @@ -75,6 +81,7 @@ public class AdvancedAppSettings extends SettingsPreferenceFragment implements C private NetworkPolicyManager mNpm; private AppOpsManager mAom; private Handler mHandler; + private PermissionsInfo mPermissionsInfo; @Override public void onCreate(Bundle icicle) { @@ -84,6 +91,7 @@ public class AdvancedAppSettings extends SettingsPreferenceFragment implements C mApplicationsState = ApplicationsState.getInstance(getActivity().getApplication()); mSession = mApplicationsState.newSession(this); + mAppPerms = findPreference(KEY_APP_PERM); mAllApps = findPreference(KEY_ALL_APPS); mResetAll = findPreference(KEY_RESET_ALL); mResetAll.setOnPreferenceClickListener(new OnPreferenceClickListener() { @@ -136,6 +144,7 @@ public class AdvancedAppSettings extends SettingsPreferenceFragment implements C public void onResume() { super.onResume(); mActivityResumed = true; + mPermissionsInfo = new PermissionsInfo(getActivity(), this); } @Override @@ -265,4 +274,11 @@ public class AdvancedAppSettings extends SettingsPreferenceFragment implements C // No-op. } + @Override + public void onPermissionLoadComplete() { + mAppPerms.setSummary(getActivity().getString(R.string.app_permissions_summary, + mPermissionsInfo.getRuntimePermAppsGrantedCount(), + mPermissionsInfo.getRuntimePermAppsCount())); + } + } diff --git a/src/com/android/settings/applications/ManagePermissions.java b/src/com/android/settings/applications/ManagePermissions.java new file mode 100644 index 000000000..8fb3e6257 --- /dev/null +++ b/src/com/android/settings/applications/ManagePermissions.java @@ -0,0 +1,117 @@ +/* + * 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.ActivityNotFoundException; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.preference.Preference; +import android.preference.Preference.OnPreferenceClickListener; +import android.preference.PreferenceScreen; +import android.util.Log; + +import com.android.internal.logging.MetricsLogger; +import com.android.settings.R; +import com.android.settings.SettingsPreferenceFragment; +import com.android.settings.applications.PermissionsInfo.PermissionGroup; + +import java.util.List; + +public class ManagePermissions extends SettingsPreferenceFragment + implements PermissionsInfo.Callback, OnPreferenceClickListener { + + private static final String TAG = "ManagePermissions"; + + private boolean mLoadComplete; + private PermissionsInfo mPermissionsInfo; + + @Override + public void onResume() { + super.onResume(); + + mPermissionsInfo = new PermissionsInfo(getActivity(), this); + } + + private void refreshUi() { + PreferenceScreen screen = getPreferenceScreen(); + if (screen == null) { + screen = getPreferenceManager().createPreferenceScreen(getActivity()); + setPreferenceScreen(screen); + } else { + screen.removeAll(); + } + final int count = screen.getPreferenceCount(); + if (count == 0) { + List<PermissionGroup> groups = mPermissionsInfo.getGroups(); + for (PermissionGroup group : groups) { + if (group.possibleApps.size() == 0) continue; + PermissionPreference pref = new PermissionPreference(getActivity(), group); + pref.refreshUi(); + screen.addPreference(pref); + } + } else { + for (int i = 0; i < count; i++) { + ((PermissionPreference) screen.getPreference(i)).refreshUi(); + } + } + } + + @Override + public void onPermissionLoadComplete() { + refreshUi(); + } + + @Override + public boolean onPreferenceClick(Preference preference) { + return true; + } + + @Override + protected int getMetricsCategory() { + return MetricsLogger.MANAGE_PERMISSIONS; + } + + private class PermissionPreference extends Preference implements OnPreferenceClickListener { + private final PermissionGroup mGroup; + + public PermissionPreference(Context context, PermissionGroup group) { + super(context); + setOnPreferenceClickListener(this); + mGroup = group; + } + + public void refreshUi() { + setTitle(mGroup.label); + setIcon(mGroup.icon); + setSummary(getContext().getString(R.string.app_permissions_group_summary, + mGroup.grantedApps.size(), mGroup.possibleApps.size())); + } + + @Override + public boolean onPreferenceClick(Preference preference) { + Intent i = new Intent(Intent.ACTION_MANAGE_PERMISSION_APPS) + .putExtra(Intent.EXTRA_PERMISSION_NAME, mGroup.name); + try { + getActivity().startActivity(i); + } catch (ActivityNotFoundException e) { + Log.w(TAG, "No app to handle " + i.getAction()); + } + return true; + } + } + +} diff --git a/src/com/android/settings/applications/PermissionsInfo.java b/src/com/android/settings/applications/PermissionsInfo.java new file mode 100644 index 000000000..8656d1a8d --- /dev/null +++ b/src/com/android/settings/applications/PermissionsInfo.java @@ -0,0 +1,188 @@ +/* + * 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.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.PermissionGroupInfo; +import android.content.pm.PermissionInfo; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.ShapeDrawable; +import android.os.AsyncTask; +import android.os.Build; +import android.os.UserHandle; +import android.os.UserManager; +import android.util.ArrayMap; +import android.util.Log; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class PermissionsInfo { + + private static final String TAG = "PermissionsInfo"; + + private final PackageManager mPm; + private final ArrayList<PermissionGroup> mGroups = new ArrayList<>(); + private final Map<String, PermissionGroup> mGroupLookup = new ArrayMap<>(); + private final Callback mCallback; + private final Context mContext; + // Count of apps that request runtime permissions. + private int mRuntimePermAppsCt; + // Count of apps that are granted runtime permissions. + private int mRuntimePermAppsGrantedCt; + + public PermissionsInfo(Context context, Callback callback) { + mContext = context; + mPm = context.getPackageManager(); + mCallback = callback; + new PermissionsLoader().execute(); + } + + public List<PermissionGroup> getGroups() { + synchronized (mGroups) { + return new ArrayList<>(mGroups); + } + } + + public int getRuntimePermAppsCount() { + return mRuntimePermAppsCt; + } + + public int getRuntimePermAppsGrantedCount() { + return mRuntimePermAppsGrantedCt; + } + + private PermissionGroup getOrCreateGroup(String permission) { + PermissionGroup group = mGroupLookup.get(permission); + if (group == null) { + // Some permissions don't have a group, in that case treat them like a group + // and create their own PermissionGroup (only if they are runtime). + try { + PermissionInfo info = mPm.getPermissionInfo(permission, 0); + if (info.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS) { + group = new PermissionGroup(); + // TODO: Add default permission icon. + group.icon = info.icon != 0 ? info.loadIcon(mPm) : new ShapeDrawable(); + group.name = info.name; + group.label = info.loadLabel(mPm).toString(); + mGroups.add(group); + mGroupLookup.put(permission, group); + } + } catch (NameNotFoundException e) { + Log.w(TAG, "Unknown permission " + permission, e); + } + } + return group; + } + + private class PermissionsLoader extends AsyncTask<Void, Void, Void> { + + @Override + protected Void doInBackground(Void... params) { + List<PermissionGroupInfo> groups = + mPm.getAllPermissionGroups(PackageManager.GET_META_DATA); + // Get the groups. + for (PermissionGroupInfo groupInfo : groups) { + PermissionGroup group = new PermissionGroup(); + // TODO: Add default permission icon. + group.icon = groupInfo.icon != 0 ? groupInfo.loadIcon(mPm) : new ShapeDrawable(); + group.name = groupInfo.name; + group.label = groupInfo.loadLabel(mPm).toString(); + synchronized (mGroups) { + mGroups.add(group); + } + } + // Load permissions and which are runtime. + for (PermissionGroup group : mGroups) { + try { + List<PermissionInfo> permissions = + mPm.queryPermissionsByGroup(group.name, 0); + for (PermissionInfo info : permissions) { + if (info.protectionLevel != PermissionInfo.PROTECTION_DANGEROUS) continue; + mGroupLookup.put(info.name, group); + } + } catch (NameNotFoundException e) { + Log.w(TAG, "Problem getting permissions", e); + } + } + // Load granted info. + for (UserHandle user : UserManager.get(mContext).getUserProfiles()) { + List<PackageInfo> allApps = mPm.getInstalledPackages( + PackageManager.GET_PERMISSIONS, user.getIdentifier()); + for (PackageInfo info : allApps) { + if (info.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1 + || info.requestedPermissions == null) { + continue; + } + final int N = info.requestedPermissionsFlags.length; + boolean appHasRuntimePerms = false; + boolean appGrantedRuntimePerms = false; + for (int i = 0; i < N; i++) { + boolean granted = (info.requestedPermissionsFlags[i] + & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0; + PermissionGroup group = getOrCreateGroup(info.requestedPermissions[i]); + String key = Integer.toString(info.applicationInfo.uid); + if (group != null && !group.possibleApps.contains(key)) { + appHasRuntimePerms = true; + group.possibleApps.add(key); + if (granted) { + appGrantedRuntimePerms = true; + group.grantedApps.add(key); + } + } + } + if (appHasRuntimePerms) { + mRuntimePermAppsCt++; + if (appGrantedRuntimePerms) { + mRuntimePermAppsGrantedCt++; + } + } + } + } + Collections.sort(mGroups); + + return null; + } + + @Override + protected void onPostExecute(Void result) { + mCallback.onPermissionLoadComplete(); + } + } + + public static class PermissionGroup implements Comparable<PermissionGroup> { + public final List<String> possibleApps = new ArrayList<>(); + public final List<String> grantedApps = new ArrayList<>(); + public String name; + public String label; + public Drawable icon; + + @Override + public int compareTo(PermissionGroup another) { + return label.compareTo(another.label); + } + } + + public interface Callback { + void onPermissionLoadComplete(); + } + +} |