Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 1 | /** |
| 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 | |
| 17 | package com.android.settings.applications; |
| 18 | |
| 19 | import android.app.AppOpsManager; |
| 20 | import android.content.Context; |
| 21 | import android.content.pm.ApplicationInfo; |
| 22 | import android.content.pm.PackageInfo; |
| 23 | import android.content.pm.PackageManager; |
| 24 | import android.content.pm.PackageManager.NameNotFoundException; |
| 25 | import android.content.res.Resources; |
| 26 | import android.graphics.drawable.Drawable; |
| 27 | import android.os.Parcel; |
| 28 | import android.os.Parcelable; |
| 29 | import android.text.format.DateUtils; |
| 30 | |
Dianne Hackborn | 0dd9902 | 2013-01-24 19:14:26 -0800 | [diff] [blame^] | 31 | import android.util.Log; |
| 32 | import android.util.SparseArray; |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 33 | import com.android.settings.R; |
| 34 | |
| 35 | import java.io.File; |
| 36 | import java.text.Collator; |
| 37 | import java.util.ArrayList; |
| 38 | import java.util.Collections; |
| 39 | import java.util.Comparator; |
| 40 | import java.util.HashMap; |
| 41 | import java.util.List; |
| 42 | |
| 43 | public class AppOpsState { |
Dianne Hackborn | 0dd9902 | 2013-01-24 19:14:26 -0800 | [diff] [blame^] | 44 | static final String TAG = "AppOpsState"; |
| 45 | static final boolean DEBUG = false; |
| 46 | |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 47 | final Context mContext; |
| 48 | final AppOpsManager mAppOps; |
| 49 | final PackageManager mPm; |
Dianne Hackborn | 0dd9902 | 2013-01-24 19:14:26 -0800 | [diff] [blame^] | 50 | final CharSequence[] mOpNames; |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 51 | |
| 52 | List<AppOpEntry> mApps; |
| 53 | |
| 54 | public AppOpsState(Context context) { |
| 55 | mContext = context; |
| 56 | mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE); |
| 57 | mPm = context.getPackageManager(); |
Dianne Hackborn | 0dd9902 | 2013-01-24 19:14:26 -0800 | [diff] [blame^] | 58 | mOpNames = context.getResources().getTextArray(R.array.app_ops_names); |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 59 | } |
| 60 | |
| 61 | public static class OpsTemplate implements Parcelable { |
| 62 | public final int[] ops; |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 63 | |
Dianne Hackborn | 0dd9902 | 2013-01-24 19:14:26 -0800 | [diff] [blame^] | 64 | public OpsTemplate(int[] _ops) { |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 65 | ops = _ops; |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 66 | } |
| 67 | |
| 68 | OpsTemplate(Parcel src) { |
| 69 | ops = src.createIntArray(); |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 70 | } |
| 71 | |
| 72 | @Override |
| 73 | public int describeContents() { |
| 74 | return 0; |
| 75 | } |
| 76 | |
| 77 | @Override |
| 78 | public void writeToParcel(Parcel dest, int flags) { |
| 79 | dest.writeIntArray(ops); |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 80 | } |
| 81 | |
| 82 | public static final Creator<OpsTemplate> CREATOR = new Creator<OpsTemplate>() { |
| 83 | @Override public OpsTemplate createFromParcel(Parcel source) { |
| 84 | return new OpsTemplate(source); |
| 85 | } |
| 86 | |
| 87 | @Override public OpsTemplate[] newArray(int size) { |
| 88 | return new OpsTemplate[size]; |
| 89 | } |
| 90 | }; |
| 91 | } |
| 92 | |
| 93 | public static final OpsTemplate LOCATION_TEMPLATE = new OpsTemplate( |
| 94 | new int[] { AppOpsManager.OP_COARSE_LOCATION, |
| 95 | AppOpsManager.OP_FINE_LOCATION, |
Dianne Hackborn | 0dd9902 | 2013-01-24 19:14:26 -0800 | [diff] [blame^] | 96 | AppOpsManager.OP_GPS, |
| 97 | AppOpsManager.OP_WIFI_SCAN } |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 98 | ); |
| 99 | |
| 100 | public static final OpsTemplate PERSONAL_TEMPLATE = new OpsTemplate( |
| 101 | new int[] { AppOpsManager.OP_READ_CONTACTS, |
| 102 | AppOpsManager.OP_WRITE_CONTACTS, |
| 103 | AppOpsManager.OP_READ_CALL_LOG, |
Dianne Hackborn | 0dd9902 | 2013-01-24 19:14:26 -0800 | [diff] [blame^] | 104 | AppOpsManager.OP_WRITE_CALL_LOG, |
| 105 | AppOpsManager.OP_READ_CALENDAR, |
| 106 | AppOpsManager.OP_WRITE_CALENDAR } |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 107 | ); |
| 108 | |
| 109 | public static final OpsTemplate DEVICE_TEMPLATE = new OpsTemplate( |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 110 | new int[] { AppOpsManager.OP_VIBRATE } |
| 111 | ); |
| 112 | |
Dianne Hackborn | 0dd9902 | 2013-01-24 19:14:26 -0800 | [diff] [blame^] | 113 | public static final OpsTemplate[] ALL_TEMPLATES = new OpsTemplate[] { |
| 114 | LOCATION_TEMPLATE, PERSONAL_TEMPLATE, DEVICE_TEMPLATE |
| 115 | }; |
| 116 | |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 117 | /** |
| 118 | * This class holds the per-item data in our Loader. |
| 119 | */ |
| 120 | public static class AppEntry { |
| 121 | private final AppOpsState mState; |
| 122 | private final ApplicationInfo mInfo; |
| 123 | private final File mApkFile; |
Dianne Hackborn | 0dd9902 | 2013-01-24 19:14:26 -0800 | [diff] [blame^] | 124 | private final SparseArray<AppOpsManager.OpEntry> mOps |
| 125 | = new SparseArray<AppOpsManager.OpEntry>(); |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 126 | private String mLabel; |
| 127 | private Drawable mIcon; |
| 128 | private boolean mMounted; |
| 129 | |
| 130 | public AppEntry(AppOpsState state, ApplicationInfo info) { |
| 131 | mState = state; |
| 132 | mInfo = info; |
| 133 | mApkFile = new File(info.sourceDir); |
| 134 | } |
| 135 | |
Dianne Hackborn | 0dd9902 | 2013-01-24 19:14:26 -0800 | [diff] [blame^] | 136 | public void addOp(AppOpsManager.OpEntry op) { |
| 137 | mOps.put(op.getOp(), op); |
| 138 | } |
| 139 | |
| 140 | public boolean hasOp(int op) { |
| 141 | return mOps.indexOfKey(op) >= 0; |
| 142 | } |
| 143 | |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 144 | public ApplicationInfo getApplicationInfo() { |
| 145 | return mInfo; |
| 146 | } |
| 147 | |
| 148 | public String getLabel() { |
| 149 | return mLabel; |
| 150 | } |
| 151 | |
| 152 | public Drawable getIcon() { |
| 153 | if (mIcon == null) { |
| 154 | if (mApkFile.exists()) { |
| 155 | mIcon = mInfo.loadIcon(mState.mPm); |
| 156 | return mIcon; |
| 157 | } else { |
| 158 | mMounted = false; |
| 159 | } |
| 160 | } else if (!mMounted) { |
| 161 | // If the app wasn't mounted but is now mounted, reload |
| 162 | // its icon. |
| 163 | if (mApkFile.exists()) { |
| 164 | mMounted = true; |
| 165 | mIcon = mInfo.loadIcon(mState.mPm); |
| 166 | return mIcon; |
| 167 | } |
| 168 | } else { |
| 169 | return mIcon; |
| 170 | } |
| 171 | |
| 172 | return mState.mContext.getResources().getDrawable( |
| 173 | android.R.drawable.sym_def_app_icon); |
| 174 | } |
| 175 | |
| 176 | @Override public String toString() { |
| 177 | return mLabel; |
| 178 | } |
| 179 | |
| 180 | void loadLabel(Context context) { |
| 181 | if (mLabel == null || !mMounted) { |
| 182 | if (!mApkFile.exists()) { |
| 183 | mMounted = false; |
| 184 | mLabel = mInfo.packageName; |
| 185 | } else { |
| 186 | mMounted = true; |
| 187 | CharSequence label = mInfo.loadLabel(context.getPackageManager()); |
| 188 | mLabel = label != null ? label.toString() : mInfo.packageName; |
| 189 | } |
| 190 | } |
| 191 | } |
| 192 | } |
| 193 | |
| 194 | /** |
| 195 | * This class holds the per-item data in our Loader. |
| 196 | */ |
| 197 | public static class AppOpEntry { |
| 198 | private final AppOpsManager.PackageOps mPkgOps; |
| 199 | private final ArrayList<AppOpsManager.OpEntry> mOps |
| 200 | = new ArrayList<AppOpsManager.OpEntry>(); |
| 201 | private final AppEntry mApp; |
| 202 | |
| 203 | public AppOpEntry(AppOpsManager.PackageOps pkg, AppOpsManager.OpEntry op, AppEntry app) { |
| 204 | mPkgOps = pkg; |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 205 | mApp = app; |
Dianne Hackborn | 0dd9902 | 2013-01-24 19:14:26 -0800 | [diff] [blame^] | 206 | mApp.addOp(op); |
| 207 | mOps.add(op); |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 208 | } |
| 209 | |
| 210 | public void addOp(AppOpsManager.OpEntry op) { |
Dianne Hackborn | 0dd9902 | 2013-01-24 19:14:26 -0800 | [diff] [blame^] | 211 | mApp.addOp(op); |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 212 | for (int i=0; i<mOps.size(); i++) { |
| 213 | AppOpsManager.OpEntry pos = mOps.get(i); |
| 214 | if (pos.isRunning() != op.isRunning()) { |
| 215 | if (op.isRunning()) { |
| 216 | mOps.add(i, op); |
| 217 | return; |
| 218 | } |
Dianne Hackborn | 0dd9902 | 2013-01-24 19:14:26 -0800 | [diff] [blame^] | 219 | continue; |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 220 | } |
Dianne Hackborn | 0dd9902 | 2013-01-24 19:14:26 -0800 | [diff] [blame^] | 221 | if (pos.getTime() < op.getTime()) { |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 222 | mOps.add(i, op); |
| 223 | return; |
| 224 | } |
| 225 | } |
| 226 | mOps.add(op); |
| 227 | } |
| 228 | |
| 229 | public AppEntry getAppEntry() { |
| 230 | return mApp; |
| 231 | } |
| 232 | |
| 233 | public AppOpsManager.PackageOps getPackageOps() { |
| 234 | return mPkgOps; |
| 235 | } |
| 236 | |
| 237 | public int getNumOpEntry() { |
| 238 | return mOps.size(); |
| 239 | } |
| 240 | |
| 241 | public AppOpsManager.OpEntry getOpEntry(int pos) { |
| 242 | return mOps.get(pos); |
| 243 | } |
| 244 | |
Dianne Hackborn | 0dd9902 | 2013-01-24 19:14:26 -0800 | [diff] [blame^] | 245 | public CharSequence getLabelText(AppOpsState state) { |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 246 | if (getNumOpEntry() == 1) { |
Dianne Hackborn | 0dd9902 | 2013-01-24 19:14:26 -0800 | [diff] [blame^] | 247 | return state.mOpNames[getOpEntry(0).getOp()]; |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 248 | } else { |
| 249 | StringBuilder builder = new StringBuilder(); |
| 250 | for (int i=0; i<getNumOpEntry(); i++) { |
| 251 | if (i > 0) { |
| 252 | builder.append(", "); |
| 253 | } |
Dianne Hackborn | 0dd9902 | 2013-01-24 19:14:26 -0800 | [diff] [blame^] | 254 | builder.append(state.mOpNames[getOpEntry(i).getOp()]); |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 255 | } |
| 256 | return builder.toString(); |
| 257 | } |
| 258 | } |
| 259 | |
| 260 | public CharSequence getTimeText(Resources res) { |
| 261 | if (isRunning()) { |
| 262 | return res.getText(R.string.app_ops_running); |
| 263 | } |
| 264 | if (getTime() > 0) { |
| 265 | return DateUtils.getRelativeTimeSpanString(getTime(), |
| 266 | System.currentTimeMillis(), |
| 267 | DateUtils.MINUTE_IN_MILLIS, |
| 268 | DateUtils.FORMAT_ABBREV_RELATIVE); |
| 269 | } |
| 270 | return ""; |
| 271 | } |
| 272 | |
| 273 | public boolean isRunning() { |
| 274 | return mOps.get(0).isRunning(); |
| 275 | } |
| 276 | |
| 277 | public long getTime() { |
| 278 | return mOps.get(0).getTime(); |
| 279 | } |
| 280 | |
| 281 | @Override public String toString() { |
| 282 | return mApp.getLabel(); |
| 283 | } |
| 284 | } |
| 285 | |
| 286 | /** |
| 287 | * Perform alphabetical comparison of application entry objects. |
| 288 | */ |
| 289 | public static final Comparator<AppOpEntry> APP_OP_COMPARATOR = new Comparator<AppOpEntry>() { |
| 290 | private final Collator sCollator = Collator.getInstance(); |
| 291 | @Override |
| 292 | public int compare(AppOpEntry object1, AppOpEntry object2) { |
| 293 | if (object1.isRunning() != object2.isRunning()) { |
| 294 | // Currently running ops go first. |
| 295 | return object1.isRunning() ? -1 : 1; |
| 296 | } |
| 297 | if (object1.getTime() != object2.getTime()) { |
| 298 | // More recent times go first. |
| 299 | return object1.getTime() > object2.getTime() ? -1 : 1; |
| 300 | } |
| 301 | return sCollator.compare(object1.getAppEntry().getLabel(), |
| 302 | object2.getAppEntry().getLabel()); |
| 303 | } |
| 304 | }; |
| 305 | |
| 306 | private void addOp(List<AppOpEntry> entries, AppOpsManager.PackageOps pkgOps, |
| 307 | AppEntry appEntry, AppOpsManager.OpEntry opEntry) { |
| 308 | if (entries.size() > 0) { |
| 309 | AppOpEntry last = entries.get(entries.size()-1); |
| 310 | if (last.getAppEntry() == appEntry) { |
| 311 | boolean lastExe = last.getTime() != 0; |
| 312 | boolean entryExe = opEntry.getTime() != 0; |
| 313 | if (lastExe == entryExe) { |
Dianne Hackborn | 0dd9902 | 2013-01-24 19:14:26 -0800 | [diff] [blame^] | 314 | if (DEBUG) Log.d(TAG, "Add op " + opEntry.getOp() + " to package " |
| 315 | + pkgOps.getPackageName() + ": append to " + last); |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 316 | last.addOp(opEntry); |
| 317 | return; |
| 318 | } |
| 319 | } |
| 320 | } |
| 321 | AppOpEntry entry = new AppOpEntry(pkgOps, opEntry, appEntry); |
Dianne Hackborn | 0dd9902 | 2013-01-24 19:14:26 -0800 | [diff] [blame^] | 322 | if (DEBUG) Log.d(TAG, "Add op " + opEntry.getOp() + " to package " |
| 323 | + pkgOps.getPackageName() + ": making new " + entry); |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 324 | entries.add(entry); |
| 325 | } |
| 326 | |
| 327 | public List<AppOpEntry> buildState(OpsTemplate tpl) { |
| 328 | return buildState(tpl, 0, null); |
| 329 | } |
| 330 | |
Dianne Hackborn | 0dd9902 | 2013-01-24 19:14:26 -0800 | [diff] [blame^] | 331 | private AppEntry getAppEntry(final Context context, final HashMap<String, AppEntry> appEntries, |
| 332 | final String packageName, ApplicationInfo appInfo) { |
| 333 | AppEntry appEntry = appEntries.get(packageName); |
| 334 | if (appEntry == null) { |
| 335 | if (appInfo == null) { |
| 336 | try { |
| 337 | appInfo = mPm.getApplicationInfo(packageName, |
| 338 | PackageManager.GET_DISABLED_COMPONENTS |
| 339 | | PackageManager.GET_UNINSTALLED_PACKAGES); |
| 340 | } catch (PackageManager.NameNotFoundException e) { |
| 341 | Log.w(TAG, "Unable to find info for package " + packageName); |
| 342 | return null; |
| 343 | } |
| 344 | } |
| 345 | appEntry = new AppEntry(this, appInfo); |
| 346 | appEntry.loadLabel(context); |
| 347 | appEntries.put(packageName, appEntry); |
| 348 | } |
| 349 | return appEntry; |
| 350 | } |
| 351 | |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 352 | public List<AppOpEntry> buildState(OpsTemplate tpl, int uid, String packageName) { |
| 353 | final Context context = mContext; |
| 354 | |
| 355 | final HashMap<String, AppEntry> appEntries = new HashMap<String, AppEntry>(); |
Dianne Hackborn | 0dd9902 | 2013-01-24 19:14:26 -0800 | [diff] [blame^] | 356 | List<AppOpEntry> entries = new ArrayList<AppOpEntry>(); |
| 357 | |
| 358 | ArrayList<String> perms = new ArrayList<String>(); |
| 359 | ArrayList<Integer> permOps = new ArrayList<Integer>(); |
| 360 | for (int i=0; i<tpl.ops.length; i++) { |
| 361 | String perm = AppOpsManager.opToPermission(tpl.ops[i]); |
| 362 | if (!perms.contains(perm)) { |
| 363 | perms.add(perm); |
| 364 | permOps.add(tpl.ops[i]); |
| 365 | } |
| 366 | } |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 367 | |
| 368 | List<AppOpsManager.PackageOps> pkgs; |
| 369 | if (packageName != null) { |
| 370 | pkgs = mAppOps.getOpsForPackage(uid, packageName, tpl.ops); |
| 371 | } else { |
| 372 | pkgs = mAppOps.getPackagesForOps(tpl.ops); |
| 373 | } |
Dianne Hackborn | 0dd9902 | 2013-01-24 19:14:26 -0800 | [diff] [blame^] | 374 | |
| 375 | if (pkgs != null) { |
| 376 | for (int i=0; i<pkgs.size(); i++) { |
| 377 | AppOpsManager.PackageOps pkgOps = pkgs.get(i); |
| 378 | AppEntry appEntry = getAppEntry(context, appEntries, pkgOps.getPackageName(), null); |
| 379 | if (appEntry == null) { |
| 380 | continue; |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 381 | } |
Dianne Hackborn | 0dd9902 | 2013-01-24 19:14:26 -0800 | [diff] [blame^] | 382 | for (int j=0; j<pkgOps.getOps().size(); j++) { |
| 383 | AppOpsManager.OpEntry opEntry = pkgOps.getOps().get(j); |
| 384 | addOp(entries, pkgOps, appEntry, opEntry); |
| 385 | } |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 386 | } |
| 387 | } |
| 388 | |
Dianne Hackborn | 0dd9902 | 2013-01-24 19:14:26 -0800 | [diff] [blame^] | 389 | List<PackageInfo> apps; |
| 390 | if (packageName != null) { |
| 391 | apps = new ArrayList<PackageInfo>(); |
| 392 | try { |
| 393 | PackageInfo pi = mPm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS); |
| 394 | apps.add(pi); |
| 395 | } catch (NameNotFoundException e) { |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 396 | } |
Dianne Hackborn | 0dd9902 | 2013-01-24 19:14:26 -0800 | [diff] [blame^] | 397 | } else { |
| 398 | String[] permsArray = new String[perms.size()]; |
| 399 | perms.toArray(permsArray); |
| 400 | apps = mPm.getPackagesHoldingPermissions(permsArray, 0); |
| 401 | } |
| 402 | for (int i=0; i<apps.size(); i++) { |
| 403 | PackageInfo appInfo = apps.get(i); |
| 404 | AppEntry appEntry = getAppEntry(context, appEntries, appInfo.packageName, |
| 405 | appInfo.applicationInfo); |
| 406 | if (appEntry == null) { |
| 407 | continue; |
| 408 | } |
| 409 | List<AppOpsManager.OpEntry> dummyOps = null; |
| 410 | AppOpsManager.PackageOps pkgOps = null; |
| 411 | for (int j=0; j<appInfo.requestedPermissions.length; j++) { |
| 412 | if (appInfo.requestedPermissionsFlags != null) { |
| 413 | if ((appInfo.requestedPermissionsFlags[j] |
| 414 | & PackageInfo.REQUESTED_PERMISSION_GRANTED) == 0) { |
| 415 | if (DEBUG) Log.d(TAG, "Pkg " + appInfo.packageName + " perm " |
| 416 | + appInfo.requestedPermissions[j] + " not granted; skipping"); |
| 417 | break; |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 418 | } |
| 419 | } |
Dianne Hackborn | 0dd9902 | 2013-01-24 19:14:26 -0800 | [diff] [blame^] | 420 | if (DEBUG) Log.d(TAG, "Pkg " + appInfo.packageName + ": requested perm " |
| 421 | + appInfo.requestedPermissions[j]); |
| 422 | for (int k=0; k<perms.size(); k++) { |
| 423 | if (!perms.get(k).equals(appInfo.requestedPermissions[j])) { |
| 424 | continue; |
| 425 | } |
| 426 | if (DEBUG) Log.d(TAG, "Pkg " + appInfo.packageName + " perm " + perms.get(k) |
| 427 | + " has op " + permOps.get(k) + ": " + appEntry.hasOp(permOps.get(k))); |
| 428 | if (appEntry.hasOp(permOps.get(k))) { |
| 429 | continue; |
| 430 | } |
| 431 | if (dummyOps == null) { |
| 432 | dummyOps = new ArrayList<AppOpsManager.OpEntry>(); |
| 433 | pkgOps = new AppOpsManager.PackageOps( |
| 434 | appInfo.packageName, appInfo.applicationInfo.uid, dummyOps); |
| 435 | |
| 436 | } |
| 437 | AppOpsManager.OpEntry opEntry = new AppOpsManager.OpEntry( |
| 438 | permOps.get(k), AppOpsManager.MODE_ALLOWED, 0, 0, 0); |
| 439 | dummyOps.add(opEntry); |
| 440 | addOp(entries, pkgOps, appEntry, opEntry); |
| 441 | } |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 442 | } |
| 443 | } |
| 444 | |
| 445 | // Sort the list. |
| 446 | Collections.sort(entries, APP_OP_COMPARATOR); |
| 447 | |
| 448 | // Done! |
| 449 | return entries; |
| 450 | } |
Dianne Hackborn | 0dd9902 | 2013-01-24 19:14:26 -0800 | [diff] [blame^] | 451 | |
| 452 | public CharSequence getLabelText(AppOpsManager.OpEntry op) { |
| 453 | return mOpNames[op.getOp()]; |
| 454 | } |
| 455 | |
| 456 | public CharSequence getTimeText(AppOpsManager.OpEntry op) { |
| 457 | if (op.isRunning()) { |
| 458 | return mContext.getResources().getText(R.string.app_ops_running); |
| 459 | } |
| 460 | if (op.getTime() > 0) { |
| 461 | return DateUtils.getRelativeTimeSpanString(op.getTime(), |
| 462 | System.currentTimeMillis(), |
| 463 | DateUtils.MINUTE_IN_MILLIS, |
| 464 | DateUtils.FORMAT_ABBREV_RELATIVE); |
| 465 | } |
| 466 | return mContext.getResources().getText(R.string.app_ops_never_used); |
| 467 | } |
| 468 | |
Dianne Hackborn | 18b64f4 | 2013-01-18 10:52:38 -0800 | [diff] [blame] | 469 | } |