blob: 61ed2f46bf4a3f3adb3d3343988a247d63b373f3 [file] [log] [blame]
Dianne Hackborn18b64f42013-01-18 10:52:38 -08001/**
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy
6 * 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, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations
14 * under the License.
15 */
16
17package com.android.settings.applications;
18
19import android.app.AppOpsManager;
20import android.content.Context;
21import android.content.pm.ApplicationInfo;
22import android.content.pm.PackageInfo;
23import android.content.pm.PackageManager;
24import android.content.pm.PackageManager.NameNotFoundException;
25import android.content.res.Resources;
26import android.graphics.drawable.Drawable;
27import android.os.Parcel;
28import android.os.Parcelable;
29import android.text.format.DateUtils;
30
Dianne Hackborn0dd99022013-01-24 19:14:26 -080031import android.util.Log;
32import android.util.SparseArray;
Dianne Hackborn18b64f42013-01-18 10:52:38 -080033import com.android.settings.R;
34
35import java.io.File;
36import java.text.Collator;
37import java.util.ArrayList;
38import java.util.Collections;
39import java.util.Comparator;
40import java.util.HashMap;
41import java.util.List;
42
43public class AppOpsState {
Dianne Hackborn0dd99022013-01-24 19:14:26 -080044 static final String TAG = "AppOpsState";
45 static final boolean DEBUG = false;
46
Dianne Hackborn18b64f42013-01-18 10:52:38 -080047 final Context mContext;
48 final AppOpsManager mAppOps;
49 final PackageManager mPm;
Dianne Hackborn8b0afc72013-02-01 17:29:15 -080050 final CharSequence[] mOpSummaries;
51 final CharSequence[] mOpLabels;
Dianne Hackborn18b64f42013-01-18 10:52:38 -080052
53 List<AppOpEntry> mApps;
54
55 public AppOpsState(Context context) {
56 mContext = context;
57 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
58 mPm = context.getPackageManager();
Dianne Hackborn8b0afc72013-02-01 17:29:15 -080059 mOpSummaries = context.getResources().getTextArray(R.array.app_ops_summaries);
60 mOpLabels = context.getResources().getTextArray(R.array.app_ops_labels);
Dianne Hackborn18b64f42013-01-18 10:52:38 -080061 }
62
63 public static class OpsTemplate implements Parcelable {
64 public final int[] ops;
Dianne Hackborn27daaab2013-01-31 15:06:57 -080065 public final boolean[] showPerms;
Dianne Hackborn18b64f42013-01-18 10:52:38 -080066
Dianne Hackborn27daaab2013-01-31 15:06:57 -080067 public OpsTemplate(int[] _ops, boolean[] _showPerms) {
Dianne Hackborn18b64f42013-01-18 10:52:38 -080068 ops = _ops;
Dianne Hackborn27daaab2013-01-31 15:06:57 -080069 showPerms = _showPerms;
Dianne Hackborn18b64f42013-01-18 10:52:38 -080070 }
71
72 OpsTemplate(Parcel src) {
73 ops = src.createIntArray();
Dianne Hackborn27daaab2013-01-31 15:06:57 -080074 showPerms = src.createBooleanArray();
Dianne Hackborn18b64f42013-01-18 10:52:38 -080075 }
76
77 @Override
78 public int describeContents() {
79 return 0;
80 }
81
82 @Override
83 public void writeToParcel(Parcel dest, int flags) {
84 dest.writeIntArray(ops);
Dianne Hackborn27daaab2013-01-31 15:06:57 -080085 dest.writeBooleanArray(showPerms);
Dianne Hackborn18b64f42013-01-18 10:52:38 -080086 }
87
88 public static final Creator<OpsTemplate> CREATOR = new Creator<OpsTemplate>() {
89 @Override public OpsTemplate createFromParcel(Parcel source) {
90 return new OpsTemplate(source);
91 }
92
93 @Override public OpsTemplate[] newArray(int size) {
94 return new OpsTemplate[size];
95 }
96 };
97 }
98
99 public static final OpsTemplate LOCATION_TEMPLATE = new OpsTemplate(
100 new int[] { AppOpsManager.OP_COARSE_LOCATION,
101 AppOpsManager.OP_FINE_LOCATION,
Dianne Hackborn0dd99022013-01-24 19:14:26 -0800102 AppOpsManager.OP_GPS,
Dianne Hackborn27daaab2013-01-31 15:06:57 -0800103 AppOpsManager.OP_WIFI_SCAN,
Dianne Hackborn15ab7752013-07-09 18:19:11 -0700104 AppOpsManager.OP_NEIGHBORING_CELLS,
105 AppOpsManager.OP_MONITOR_LOCATION },
Dianne Hackborn27daaab2013-01-31 15:06:57 -0800106 new boolean[] { true,
107 true,
108 false,
109 false,
Dianne Hackborn15ab7752013-07-09 18:19:11 -0700110 false,
Dianne Hackborn27daaab2013-01-31 15:06:57 -0800111 false }
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800112 );
113
114 public static final OpsTemplate PERSONAL_TEMPLATE = new OpsTemplate(
115 new int[] { AppOpsManager.OP_READ_CONTACTS,
116 AppOpsManager.OP_WRITE_CONTACTS,
117 AppOpsManager.OP_READ_CALL_LOG,
Dianne Hackborn0dd99022013-01-24 19:14:26 -0800118 AppOpsManager.OP_WRITE_CALL_LOG,
119 AppOpsManager.OP_READ_CALENDAR,
Dianne Hackborn782c3de2013-02-25 18:03:06 -0800120 AppOpsManager.OP_WRITE_CALENDAR,
121 AppOpsManager.OP_READ_CLIPBOARD,
122 AppOpsManager.OP_WRITE_CLIPBOARD },
Dianne Hackborn27daaab2013-01-31 15:06:57 -0800123 new boolean[] { true,
124 true,
125 true,
126 true,
127 true,
Dianne Hackborn782c3de2013-02-25 18:03:06 -0800128 true,
129 false,
130 false }
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800131 );
132
Dianne Hackborn98337872013-02-04 18:27:40 -0800133 public static final OpsTemplate MESSAGING_TEMPLATE = new OpsTemplate(
134 new int[] { AppOpsManager.OP_READ_SMS,
135 AppOpsManager.OP_RECEIVE_SMS,
136 AppOpsManager.OP_RECEIVE_EMERGECY_SMS,
137 AppOpsManager.OP_RECEIVE_MMS,
138 AppOpsManager.OP_RECEIVE_WAP_PUSH,
139 AppOpsManager.OP_WRITE_SMS,
140 AppOpsManager.OP_SEND_SMS,
141 AppOpsManager.OP_READ_ICC_SMS,
142 AppOpsManager.OP_WRITE_ICC_SMS },
143 new boolean[] { true,
144 true,
145 true,
146 true,
147 true,
148 true,
149 true,
150 true,
151 true }
152 );
153
Dianne Hackborn6e91bab2013-04-30 15:06:22 -0700154 public static final OpsTemplate MEDIA_TEMPLATE = new OpsTemplate(
Daniel Sandlerdf3f6d62013-01-30 14:03:58 -0500155 new int[] { AppOpsManager.OP_VIBRATE,
Dianne Hackborn6e91bab2013-04-30 15:06:22 -0700156 AppOpsManager.OP_CAMERA,
157 AppOpsManager.OP_RECORD_AUDIO,
158 AppOpsManager.OP_PLAY_AUDIO,
159 AppOpsManager.OP_TAKE_MEDIA_BUTTONS,
160 AppOpsManager.OP_TAKE_AUDIO_FOCUS,
161 AppOpsManager.OP_AUDIO_MASTER_VOLUME,
162 AppOpsManager.OP_AUDIO_VOICE_VOLUME,
163 AppOpsManager.OP_AUDIO_RING_VOLUME,
164 AppOpsManager.OP_AUDIO_MEDIA_VOLUME,
165 AppOpsManager.OP_AUDIO_ALARM_VOLUME,
166 AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME,
167 AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME, },
168 new boolean[] { false,
169 true,
170 true,
171 false,
172 false,
173 false,
174 false,
175 false,
176 false,
177 false,
178 false,
179 false,
180 false }
181 );
182
183 public static final OpsTemplate DEVICE_TEMPLATE = new OpsTemplate(
184 new int[] { AppOpsManager.OP_POST_NOTIFICATION,
Daniel Sandler328e2d22013-01-17 13:14:02 -0500185 AppOpsManager.OP_ACCESS_NOTIFICATIONS,
Dianne Hackborn3b13d2b2013-02-05 17:31:10 -0800186 AppOpsManager.OP_CALL_PHONE,
Dianne Hackbornd69e8dc2013-02-07 00:01:10 -0800187 AppOpsManager.OP_WRITE_SETTINGS,
Dianne Hackbornec74da62013-05-17 11:28:30 -0700188 AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
189 AppOpsManager.OP_WAKE_LOCK },
Dianne Hackborn27daaab2013-01-31 15:06:57 -0800190 new boolean[] { false,
Dianne Hackborn3b13d2b2013-02-05 17:31:10 -0800191 true,
Dianne Hackbornd69e8dc2013-02-07 00:01:10 -0800192 true,
Dianne Hackborn7ff56d32013-02-13 11:02:12 -0800193 true,
Dianne Hackbornec74da62013-05-17 11:28:30 -0700194 true,
195 true, }
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800196 );
197
Dianne Hackborn0dd99022013-01-24 19:14:26 -0800198 public static final OpsTemplate[] ALL_TEMPLATES = new OpsTemplate[] {
Dianne Hackborn6e91bab2013-04-30 15:06:22 -0700199 LOCATION_TEMPLATE, PERSONAL_TEMPLATE, MESSAGING_TEMPLATE,
200 MEDIA_TEMPLATE, DEVICE_TEMPLATE
Dianne Hackborn0dd99022013-01-24 19:14:26 -0800201 };
202
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800203 /**
204 * This class holds the per-item data in our Loader.
205 */
206 public static class AppEntry {
207 private final AppOpsState mState;
208 private final ApplicationInfo mInfo;
209 private final File mApkFile;
Dianne Hackborn0dd99022013-01-24 19:14:26 -0800210 private final SparseArray<AppOpsManager.OpEntry> mOps
211 = new SparseArray<AppOpsManager.OpEntry>();
Dianne Hackborn27daaab2013-01-31 15:06:57 -0800212 private final SparseArray<AppOpEntry> mOpSwitches
213 = new SparseArray<AppOpEntry>();
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800214 private String mLabel;
215 private Drawable mIcon;
216 private boolean mMounted;
217
218 public AppEntry(AppOpsState state, ApplicationInfo info) {
219 mState = state;
220 mInfo = info;
221 mApkFile = new File(info.sourceDir);
222 }
223
Dianne Hackborn27daaab2013-01-31 15:06:57 -0800224 public void addOp(AppOpEntry entry, AppOpsManager.OpEntry op) {
Dianne Hackborn0dd99022013-01-24 19:14:26 -0800225 mOps.put(op.getOp(), op);
Dianne Hackborn27daaab2013-01-31 15:06:57 -0800226 mOpSwitches.put(AppOpsManager.opToSwitch(op.getOp()), entry);
Dianne Hackborn0dd99022013-01-24 19:14:26 -0800227 }
228
229 public boolean hasOp(int op) {
230 return mOps.indexOfKey(op) >= 0;
231 }
232
Dianne Hackborn27daaab2013-01-31 15:06:57 -0800233 public AppOpEntry getOpSwitch(int op) {
234 return mOpSwitches.get(AppOpsManager.opToSwitch(op));
235 }
236
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800237 public ApplicationInfo getApplicationInfo() {
238 return mInfo;
239 }
240
241 public String getLabel() {
242 return mLabel;
243 }
244
245 public Drawable getIcon() {
246 if (mIcon == null) {
247 if (mApkFile.exists()) {
248 mIcon = mInfo.loadIcon(mState.mPm);
249 return mIcon;
250 } else {
251 mMounted = false;
252 }
253 } else if (!mMounted) {
254 // If the app wasn't mounted but is now mounted, reload
255 // its icon.
256 if (mApkFile.exists()) {
257 mMounted = true;
258 mIcon = mInfo.loadIcon(mState.mPm);
259 return mIcon;
260 }
261 } else {
262 return mIcon;
263 }
264
265 return mState.mContext.getResources().getDrawable(
266 android.R.drawable.sym_def_app_icon);
267 }
268
269 @Override public String toString() {
270 return mLabel;
271 }
272
273 void loadLabel(Context context) {
274 if (mLabel == null || !mMounted) {
275 if (!mApkFile.exists()) {
276 mMounted = false;
277 mLabel = mInfo.packageName;
278 } else {
279 mMounted = true;
280 CharSequence label = mInfo.loadLabel(context.getPackageManager());
281 mLabel = label != null ? label.toString() : mInfo.packageName;
282 }
283 }
284 }
285 }
286
287 /**
288 * This class holds the per-item data in our Loader.
289 */
290 public static class AppOpEntry {
291 private final AppOpsManager.PackageOps mPkgOps;
292 private final ArrayList<AppOpsManager.OpEntry> mOps
293 = new ArrayList<AppOpsManager.OpEntry>();
Dianne Hackborn8b0afc72013-02-01 17:29:15 -0800294 private final ArrayList<AppOpsManager.OpEntry> mSwitchOps
Dianne Hackborn27daaab2013-01-31 15:06:57 -0800295 = new ArrayList<AppOpsManager.OpEntry>();
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800296 private final AppEntry mApp;
Dianne Hackbornd69e8dc2013-02-07 00:01:10 -0800297 private final int mSwitchOrder;
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800298
Dianne Hackbornd69e8dc2013-02-07 00:01:10 -0800299 public AppOpEntry(AppOpsManager.PackageOps pkg, AppOpsManager.OpEntry op, AppEntry app,
300 int switchOrder) {
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800301 mPkgOps = pkg;
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800302 mApp = app;
Dianne Hackbornd69e8dc2013-02-07 00:01:10 -0800303 mSwitchOrder = switchOrder;
Dianne Hackborn27daaab2013-01-31 15:06:57 -0800304 mApp.addOp(this, op);
Dianne Hackborn0dd99022013-01-24 19:14:26 -0800305 mOps.add(op);
Dianne Hackborn8b0afc72013-02-01 17:29:15 -0800306 mSwitchOps.add(op);
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800307 }
308
Dianne Hackborn27daaab2013-01-31 15:06:57 -0800309 private static void addOp(ArrayList<AppOpsManager.OpEntry> list, AppOpsManager.OpEntry op) {
310 for (int i=0; i<list.size(); i++) {
311 AppOpsManager.OpEntry pos = list.get(i);
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800312 if (pos.isRunning() != op.isRunning()) {
313 if (op.isRunning()) {
Dianne Hackborn27daaab2013-01-31 15:06:57 -0800314 list.add(i, op);
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800315 return;
316 }
Dianne Hackborn0dd99022013-01-24 19:14:26 -0800317 continue;
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800318 }
Dianne Hackborn0dd99022013-01-24 19:14:26 -0800319 if (pos.getTime() < op.getTime()) {
Dianne Hackborn27daaab2013-01-31 15:06:57 -0800320 list.add(i, op);
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800321 return;
322 }
323 }
Dianne Hackborn27daaab2013-01-31 15:06:57 -0800324 list.add(op);
325 }
326
Dianne Hackborn8b0afc72013-02-01 17:29:15 -0800327 public void addOp(AppOpsManager.OpEntry op) {
Dianne Hackborn27daaab2013-01-31 15:06:57 -0800328 mApp.addOp(this, op);
329 addOp(mOps, op);
Dianne Hackborn8b0afc72013-02-01 17:29:15 -0800330 if (mApp.getOpSwitch(AppOpsManager.opToSwitch(op.getOp())) == null) {
331 addOp(mSwitchOps, op);
Dianne Hackborn27daaab2013-01-31 15:06:57 -0800332 }
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800333 }
334
335 public AppEntry getAppEntry() {
336 return mApp;
337 }
338
Dianne Hackbornd69e8dc2013-02-07 00:01:10 -0800339 public int getSwitchOrder() {
340 return mSwitchOrder;
341 }
342
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800343 public AppOpsManager.PackageOps getPackageOps() {
344 return mPkgOps;
345 }
346
347 public int getNumOpEntry() {
348 return mOps.size();
349 }
350
351 public AppOpsManager.OpEntry getOpEntry(int pos) {
352 return mOps.get(pos);
353 }
354
Dianne Hackborn8b0afc72013-02-01 17:29:15 -0800355 private CharSequence getCombinedText(ArrayList<AppOpsManager.OpEntry> ops,
356 CharSequence[] items) {
Dianne Hackborn27daaab2013-01-31 15:06:57 -0800357 if (ops.size() == 1) {
Dianne Hackborn8b0afc72013-02-01 17:29:15 -0800358 return items[ops.get(0).getOp()];
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800359 } else {
360 StringBuilder builder = new StringBuilder();
Dianne Hackborn27daaab2013-01-31 15:06:57 -0800361 for (int i=0; i<ops.size(); i++) {
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800362 if (i > 0) {
363 builder.append(", ");
364 }
Dianne Hackborn8b0afc72013-02-01 17:29:15 -0800365 builder.append(items[ops.get(i).getOp()]);
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800366 }
367 return builder.toString();
368 }
369 }
370
Dianne Hackborn8b0afc72013-02-01 17:29:15 -0800371 public CharSequence getSummaryText(AppOpsState state) {
372 return getCombinedText(mOps, state.mOpSummaries);
Dianne Hackborn27daaab2013-01-31 15:06:57 -0800373 }
374
Dianne Hackborn8b0afc72013-02-01 17:29:15 -0800375 public CharSequence getSwitchText(AppOpsState state) {
376 if (mSwitchOps.size() > 0) {
377 return getCombinedText(mSwitchOps, state.mOpLabels);
Dianne Hackborn27daaab2013-01-31 15:06:57 -0800378 } else {
Dianne Hackborn8b0afc72013-02-01 17:29:15 -0800379 return getCombinedText(mOps, state.mOpLabels);
Dianne Hackborn27daaab2013-01-31 15:06:57 -0800380 }
381 }
382
Dianne Hackborn8b0afc72013-02-01 17:29:15 -0800383 public CharSequence getTimeText(Resources res, boolean showEmptyText) {
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800384 if (isRunning()) {
385 return res.getText(R.string.app_ops_running);
386 }
387 if (getTime() > 0) {
388 return DateUtils.getRelativeTimeSpanString(getTime(),
389 System.currentTimeMillis(),
390 DateUtils.MINUTE_IN_MILLIS,
391 DateUtils.FORMAT_ABBREV_RELATIVE);
392 }
Dianne Hackborn8b0afc72013-02-01 17:29:15 -0800393 return showEmptyText ? res.getText(R.string.app_ops_never_used) : "";
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800394 }
395
396 public boolean isRunning() {
397 return mOps.get(0).isRunning();
398 }
399
400 public long getTime() {
401 return mOps.get(0).getTime();
402 }
403
404 @Override public String toString() {
405 return mApp.getLabel();
406 }
407 }
408
409 /**
410 * Perform alphabetical comparison of application entry objects.
411 */
412 public static final Comparator<AppOpEntry> APP_OP_COMPARATOR = new Comparator<AppOpEntry>() {
413 private final Collator sCollator = Collator.getInstance();
414 @Override
415 public int compare(AppOpEntry object1, AppOpEntry object2) {
Dianne Hackbornd69e8dc2013-02-07 00:01:10 -0800416 if (object1.getSwitchOrder() != object2.getSwitchOrder()) {
417 return object1.getSwitchOrder() < object2.getSwitchOrder() ? -1 : 1;
418 }
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800419 if (object1.isRunning() != object2.isRunning()) {
420 // Currently running ops go first.
421 return object1.isRunning() ? -1 : 1;
422 }
423 if (object1.getTime() != object2.getTime()) {
424 // More recent times go first.
425 return object1.getTime() > object2.getTime() ? -1 : 1;
426 }
427 return sCollator.compare(object1.getAppEntry().getLabel(),
428 object2.getAppEntry().getLabel());
429 }
430 };
431
432 private void addOp(List<AppOpEntry> entries, AppOpsManager.PackageOps pkgOps,
Dianne Hackbornd69e8dc2013-02-07 00:01:10 -0800433 AppEntry appEntry, AppOpsManager.OpEntry opEntry, boolean allowMerge, int switchOrder) {
Dianne Hackborn27daaab2013-01-31 15:06:57 -0800434 if (allowMerge && entries.size() > 0) {
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800435 AppOpEntry last = entries.get(entries.size()-1);
436 if (last.getAppEntry() == appEntry) {
437 boolean lastExe = last.getTime() != 0;
438 boolean entryExe = opEntry.getTime() != 0;
439 if (lastExe == entryExe) {
Dianne Hackborn0dd99022013-01-24 19:14:26 -0800440 if (DEBUG) Log.d(TAG, "Add op " + opEntry.getOp() + " to package "
441 + pkgOps.getPackageName() + ": append to " + last);
Dianne Hackborn8b0afc72013-02-01 17:29:15 -0800442 last.addOp(opEntry);
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800443 return;
444 }
445 }
446 }
Dianne Hackborn27daaab2013-01-31 15:06:57 -0800447 AppOpEntry entry = appEntry.getOpSwitch(opEntry.getOp());
448 if (entry != null) {
Dianne Hackborn8b0afc72013-02-01 17:29:15 -0800449 entry.addOp(opEntry);
Dianne Hackborn27daaab2013-01-31 15:06:57 -0800450 return;
451 }
Dianne Hackbornd69e8dc2013-02-07 00:01:10 -0800452 entry = new AppOpEntry(pkgOps, opEntry, appEntry, switchOrder);
Dianne Hackborn0dd99022013-01-24 19:14:26 -0800453 if (DEBUG) Log.d(TAG, "Add op " + opEntry.getOp() + " to package "
454 + pkgOps.getPackageName() + ": making new " + entry);
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800455 entries.add(entry);
456 }
457
458 public List<AppOpEntry> buildState(OpsTemplate tpl) {
459 return buildState(tpl, 0, null);
460 }
461
Dianne Hackborn0dd99022013-01-24 19:14:26 -0800462 private AppEntry getAppEntry(final Context context, final HashMap<String, AppEntry> appEntries,
463 final String packageName, ApplicationInfo appInfo) {
464 AppEntry appEntry = appEntries.get(packageName);
465 if (appEntry == null) {
466 if (appInfo == null) {
467 try {
468 appInfo = mPm.getApplicationInfo(packageName,
469 PackageManager.GET_DISABLED_COMPONENTS
470 | PackageManager.GET_UNINSTALLED_PACKAGES);
471 } catch (PackageManager.NameNotFoundException e) {
472 Log.w(TAG, "Unable to find info for package " + packageName);
473 return null;
474 }
475 }
476 appEntry = new AppEntry(this, appInfo);
477 appEntry.loadLabel(context);
478 appEntries.put(packageName, appEntry);
479 }
480 return appEntry;
481 }
482
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800483 public List<AppOpEntry> buildState(OpsTemplate tpl, int uid, String packageName) {
484 final Context context = mContext;
485
486 final HashMap<String, AppEntry> appEntries = new HashMap<String, AppEntry>();
Dianne Hackborn27daaab2013-01-31 15:06:57 -0800487 final List<AppOpEntry> entries = new ArrayList<AppOpEntry>();
Dianne Hackborn0dd99022013-01-24 19:14:26 -0800488
Dianne Hackborn27daaab2013-01-31 15:06:57 -0800489 final ArrayList<String> perms = new ArrayList<String>();
490 final ArrayList<Integer> permOps = new ArrayList<Integer>();
Dianne Hackbornd69e8dc2013-02-07 00:01:10 -0800491 final int[] opToOrder = new int[AppOpsManager._NUM_OP];
Dianne Hackborn0dd99022013-01-24 19:14:26 -0800492 for (int i=0; i<tpl.ops.length; i++) {
Dianne Hackborn27daaab2013-01-31 15:06:57 -0800493 if (tpl.showPerms[i]) {
494 String perm = AppOpsManager.opToPermission(tpl.ops[i]);
495 if (perm != null && !perms.contains(perm)) {
496 perms.add(perm);
497 permOps.add(tpl.ops[i]);
Dianne Hackbornd69e8dc2013-02-07 00:01:10 -0800498 opToOrder[tpl.ops[i]] = i;
Dianne Hackborn27daaab2013-01-31 15:06:57 -0800499 }
Dianne Hackborn0dd99022013-01-24 19:14:26 -0800500 }
501 }
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800502
503 List<AppOpsManager.PackageOps> pkgs;
504 if (packageName != null) {
505 pkgs = mAppOps.getOpsForPackage(uid, packageName, tpl.ops);
506 } else {
507 pkgs = mAppOps.getPackagesForOps(tpl.ops);
508 }
Dianne Hackborn0dd99022013-01-24 19:14:26 -0800509
510 if (pkgs != null) {
511 for (int i=0; i<pkgs.size(); i++) {
512 AppOpsManager.PackageOps pkgOps = pkgs.get(i);
513 AppEntry appEntry = getAppEntry(context, appEntries, pkgOps.getPackageName(), null);
514 if (appEntry == null) {
515 continue;
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800516 }
Dianne Hackborn0dd99022013-01-24 19:14:26 -0800517 for (int j=0; j<pkgOps.getOps().size(); j++) {
518 AppOpsManager.OpEntry opEntry = pkgOps.getOps().get(j);
Dianne Hackbornd69e8dc2013-02-07 00:01:10 -0800519 addOp(entries, pkgOps, appEntry, opEntry, packageName == null,
520 packageName == null ? 0 : opToOrder[opEntry.getOp()]);
Dianne Hackborn0dd99022013-01-24 19:14:26 -0800521 }
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800522 }
523 }
524
Dianne Hackborn0dd99022013-01-24 19:14:26 -0800525 List<PackageInfo> apps;
526 if (packageName != null) {
527 apps = new ArrayList<PackageInfo>();
528 try {
529 PackageInfo pi = mPm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS);
530 apps.add(pi);
531 } catch (NameNotFoundException e) {
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800532 }
Dianne Hackborn0dd99022013-01-24 19:14:26 -0800533 } else {
534 String[] permsArray = new String[perms.size()];
535 perms.toArray(permsArray);
536 apps = mPm.getPackagesHoldingPermissions(permsArray, 0);
537 }
538 for (int i=0; i<apps.size(); i++) {
539 PackageInfo appInfo = apps.get(i);
540 AppEntry appEntry = getAppEntry(context, appEntries, appInfo.packageName,
541 appInfo.applicationInfo);
542 if (appEntry == null) {
543 continue;
544 }
545 List<AppOpsManager.OpEntry> dummyOps = null;
546 AppOpsManager.PackageOps pkgOps = null;
Daniel Sandler7d3a4c12013-01-31 15:22:51 -0500547 if (appInfo.requestedPermissions != null) {
548 for (int j=0; j<appInfo.requestedPermissions.length; j++) {
549 if (appInfo.requestedPermissionsFlags != null) {
550 if ((appInfo.requestedPermissionsFlags[j]
551 & PackageInfo.REQUESTED_PERMISSION_GRANTED) == 0) {
552 if (DEBUG) Log.d(TAG, "Pkg " + appInfo.packageName + " perm "
553 + appInfo.requestedPermissions[j] + " not granted; skipping");
554 break;
555 }
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800556 }
Daniel Sandler7d3a4c12013-01-31 15:22:51 -0500557 if (DEBUG) Log.d(TAG, "Pkg " + appInfo.packageName + ": requested perm "
558 + appInfo.requestedPermissions[j]);
559 for (int k=0; k<perms.size(); k++) {
560 if (!perms.get(k).equals(appInfo.requestedPermissions[j])) {
561 continue;
562 }
563 if (DEBUG) Log.d(TAG, "Pkg " + appInfo.packageName + " perm " + perms.get(k)
564 + " has op " + permOps.get(k) + ": " + appEntry.hasOp(permOps.get(k)));
565 if (appEntry.hasOp(permOps.get(k))) {
566 continue;
567 }
568 if (dummyOps == null) {
569 dummyOps = new ArrayList<AppOpsManager.OpEntry>();
570 pkgOps = new AppOpsManager.PackageOps(
571 appInfo.packageName, appInfo.applicationInfo.uid, dummyOps);
Dianne Hackborn0dd99022013-01-24 19:14:26 -0800572
Daniel Sandler7d3a4c12013-01-31 15:22:51 -0500573 }
574 AppOpsManager.OpEntry opEntry = new AppOpsManager.OpEntry(
575 permOps.get(k), AppOpsManager.MODE_ALLOWED, 0, 0, 0);
576 dummyOps.add(opEntry);
Dianne Hackbornd69e8dc2013-02-07 00:01:10 -0800577 addOp(entries, pkgOps, appEntry, opEntry, packageName == null,
578 packageName == null ? 0 : opToOrder[opEntry.getOp()]);
Dianne Hackborn0dd99022013-01-24 19:14:26 -0800579 }
Dianne Hackborn0dd99022013-01-24 19:14:26 -0800580 }
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800581 }
582 }
583
584 // Sort the list.
585 Collections.sort(entries, APP_OP_COMPARATOR);
586
587 // Done!
588 return entries;
589 }
Dianne Hackborn18b64f42013-01-18 10:52:38 -0800590}