/* * 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.settingslib.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 mGroups = new ArrayList<>(); private final Map 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 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 { @Override protected Void doInBackground(Void... params) { List 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 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 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 { public final List possibleApps = new ArrayList<>(); public final List 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(); } }