blob: 60b5ba581f5d8d3774286f8a50b2d732207a6b71 [file] [log] [blame]
Tony Mantler618f3c42015-04-16 15:42:24 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.settingslib.applications;
17
18import android.content.Context;
19import android.content.pm.PackageInfo;
20import android.content.pm.PackageManager;
21import android.content.pm.PackageManager.NameNotFoundException;
22import android.content.pm.PermissionGroupInfo;
23import android.content.pm.PermissionInfo;
24import android.graphics.drawable.Drawable;
25import android.graphics.drawable.ShapeDrawable;
26import android.os.AsyncTask;
27import android.os.Build;
28import android.os.UserHandle;
29import android.os.UserManager;
30import android.util.ArrayMap;
31import android.util.Log;
32
33import java.util.ArrayList;
34import java.util.Collections;
35import java.util.List;
36import java.util.Map;
37
38public class PermissionsInfo {
39
40 private static final String TAG = "PermissionsInfo";
41
42 private final PackageManager mPm;
43 private final ArrayList<PermissionGroup> mGroups = new ArrayList<>();
44 private final Map<String, PermissionGroup> mGroupLookup = new ArrayMap<>();
45 private final Callback mCallback;
46 private final Context mContext;
47 // Count of apps that request runtime permissions.
48 private int mRuntimePermAppsCt;
49 // Count of apps that are granted runtime permissions.
50 private int mRuntimePermAppsGrantedCt;
51
52 public PermissionsInfo(Context context, Callback callback) {
53 mContext = context;
54 mPm = context.getPackageManager();
55 mCallback = callback;
56 new PermissionsLoader().execute();
57 }
58
59 public List<PermissionGroup> getGroups() {
60 synchronized (mGroups) {
61 return new ArrayList<>(mGroups);
62 }
63 }
64
65 public int getRuntimePermAppsCount() {
66 return mRuntimePermAppsCt;
67 }
68
69 public int getRuntimePermAppsGrantedCount() {
70 return mRuntimePermAppsGrantedCt;
71 }
72
73 private PermissionGroup getOrCreateGroup(String permission) {
74 PermissionGroup group = mGroupLookup.get(permission);
75 if (group == null) {
76 // Some permissions don't have a group, in that case treat them like a group
77 // and create their own PermissionGroup (only if they are runtime).
78 try {
79 PermissionInfo info = mPm.getPermissionInfo(permission, 0);
80 if (info.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS) {
81 group = new PermissionGroup();
82 // TODO: Add default permission icon.
83 group.icon = info.icon != 0 ? info.loadIcon(mPm) : new ShapeDrawable();
84 group.name = info.name;
85 group.label = info.loadLabel(mPm).toString();
86 mGroups.add(group);
87 mGroupLookup.put(permission, group);
88 }
89 } catch (NameNotFoundException e) {
90 Log.w(TAG, "Unknown permission " + permission, e);
91 }
92 }
93 return group;
94 }
95
96 private class PermissionsLoader extends AsyncTask<Void, Void, Void> {
97
98 @Override
99 protected Void doInBackground(Void... params) {
100 List<PermissionGroupInfo> groups =
101 mPm.getAllPermissionGroups(PackageManager.GET_META_DATA);
102 // Get the groups.
103 for (PermissionGroupInfo groupInfo : groups) {
104 PermissionGroup group = new PermissionGroup();
105 // TODO: Add default permission icon.
106 group.icon = groupInfo.icon != 0 ? groupInfo.loadIcon(mPm) : new ShapeDrawable();
107 group.name = groupInfo.name;
108 group.label = groupInfo.loadLabel(mPm).toString();
109 synchronized (mGroups) {
110 mGroups.add(group);
111 }
112 }
113 // Load permissions and which are runtime.
114 for (PermissionGroup group : mGroups) {
115 try {
116 List<PermissionInfo> permissions =
117 mPm.queryPermissionsByGroup(group.name, 0);
118 for (PermissionInfo info : permissions) {
119 if (info.protectionLevel != PermissionInfo.PROTECTION_DANGEROUS) continue;
120 mGroupLookup.put(info.name, group);
121 }
122 } catch (NameNotFoundException e) {
123 Log.w(TAG, "Problem getting permissions", e);
124 }
125 }
126 // Load granted info.
127 for (UserHandle user : UserManager.get(mContext).getUserProfiles()) {
128 List<PackageInfo> allApps = mPm.getInstalledPackages(
129 PackageManager.GET_PERMISSIONS, user.getIdentifier());
130 for (PackageInfo info : allApps) {
131 if (info.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1
132 || info.requestedPermissions == null) {
133 continue;
134 }
135 final int N = info.requestedPermissionsFlags.length;
136 boolean appHasRuntimePerms = false;
137 boolean appGrantedRuntimePerms = false;
138 for (int i = 0; i < N; i++) {
139 boolean granted = (info.requestedPermissionsFlags[i]
140 & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0;
141 PermissionGroup group = getOrCreateGroup(info.requestedPermissions[i]);
142 String key = Integer.toString(info.applicationInfo.uid);
143 if (group != null && !group.possibleApps.contains(key)) {
144 appHasRuntimePerms = true;
145 group.possibleApps.add(key);
146 if (granted) {
147 appGrantedRuntimePerms = true;
148 group.grantedApps.add(key);
149 }
150 }
151 }
152 if (appHasRuntimePerms) {
153 mRuntimePermAppsCt++;
154 if (appGrantedRuntimePerms) {
155 mRuntimePermAppsGrantedCt++;
156 }
157 }
158 }
159 }
160 Collections.sort(mGroups);
161
162 return null;
163 }
164
165 @Override
166 protected void onPostExecute(Void result) {
167 mCallback.onPermissionLoadComplete();
168 }
169 }
170
171 public static class PermissionGroup implements Comparable<PermissionGroup> {
172 public final List<String> possibleApps = new ArrayList<>();
173 public final List<String> grantedApps = new ArrayList<>();
174 public String name;
175 public String label;
176 public Drawable icon;
177
178 @Override
179 public int compareTo(PermissionGroup another) {
180 return label.compareTo(another.label);
181 }
182 }
183
184 public interface Callback {
185 void onPermissionLoadComplete();
186 }
187
188}