118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn/**
218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn * Copyright (C) 2013 The Android Open Source Project
318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn *
418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License"); you may not
518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn * use this file except in compliance with the License. You may obtain a copy
618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn * of the License at
718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn *
818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn * http://www.apache.org/licenses/LICENSE-2.0
918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn *
1018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn * Unless required by applicable law or agreed to in writing, software
1118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
1218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
1318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn * License for the specific language governing permissions and limitations
1418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn * under the License.
1518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn */
1618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
1718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackbornpackage com.android.settings.applications;
1818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
1918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackbornimport android.app.AppOpsManager;
2018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackbornimport android.content.Context;
2118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackbornimport android.content.pm.ApplicationInfo;
2218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackbornimport android.content.pm.PackageInfo;
2318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackbornimport android.content.pm.PackageManager;
2418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackbornimport android.content.pm.PackageManager.NameNotFoundException;
2518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackbornimport android.content.res.Resources;
2618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackbornimport android.graphics.drawable.Drawable;
2718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackbornimport android.os.Parcel;
2818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackbornimport android.os.Parcelable;
2918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackbornimport android.text.format.DateUtils;
3018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
310dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackbornimport android.util.Log;
320dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackbornimport android.util.SparseArray;
3318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackbornimport com.android.settings.R;
3418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
3518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackbornimport java.io.File;
3618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackbornimport java.text.Collator;
3718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackbornimport java.util.ArrayList;
3818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackbornimport java.util.Collections;
3918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackbornimport java.util.Comparator;
4018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackbornimport java.util.HashMap;
4118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackbornimport java.util.List;
4218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
4318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackbornpublic class AppOpsState {
440dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn    static final String TAG = "AppOpsState";
450dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn    static final boolean DEBUG = false;
460dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn
4718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    final Context mContext;
4818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    final AppOpsManager mAppOps;
4918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    final PackageManager mPm;
508b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn    final CharSequence[] mOpSummaries;
518b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn    final CharSequence[] mOpLabels;
5218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
5318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    List<AppOpEntry> mApps;
5418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
5518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    public AppOpsState(Context context) {
5618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        mContext = context;
5718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
5818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        mPm = context.getPackageManager();
598b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn        mOpSummaries = context.getResources().getTextArray(R.array.app_ops_summaries);
608b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn        mOpLabels = context.getResources().getTextArray(R.array.app_ops_labels);
6118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    }
6218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
6318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    public static class OpsTemplate implements Parcelable {
6418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        public final int[] ops;
6527daaab633a80be50863e6539e947db674090662Dianne Hackborn        public final boolean[] showPerms;
6618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
6727daaab633a80be50863e6539e947db674090662Dianne Hackborn        public OpsTemplate(int[] _ops, boolean[] _showPerms) {
6818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            ops = _ops;
6927daaab633a80be50863e6539e947db674090662Dianne Hackborn            showPerms = _showPerms;
7018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
7118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
7218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        OpsTemplate(Parcel src) {
7318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            ops = src.createIntArray();
7427daaab633a80be50863e6539e947db674090662Dianne Hackborn            showPerms = src.createBooleanArray();
7518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
7618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
7718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        @Override
7818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        public int describeContents() {
7918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            return 0;
8018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
8118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
8218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        @Override
8318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        public void writeToParcel(Parcel dest, int flags) {
8418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            dest.writeIntArray(ops);
8527daaab633a80be50863e6539e947db674090662Dianne Hackborn            dest.writeBooleanArray(showPerms);
8618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
8718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
8818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        public static final Creator<OpsTemplate> CREATOR = new Creator<OpsTemplate>() {
8918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            @Override public OpsTemplate createFromParcel(Parcel source) {
9018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                return new OpsTemplate(source);
9118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            }
9218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
9318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            @Override public OpsTemplate[] newArray(int size) {
9418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                return new OpsTemplate[size];
9518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            }
9618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        };
9718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    }
9818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
9918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    public static final OpsTemplate LOCATION_TEMPLATE = new OpsTemplate(
10018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            new int[] { AppOpsManager.OP_COARSE_LOCATION,
10118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    AppOpsManager.OP_FINE_LOCATION,
1020dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                    AppOpsManager.OP_GPS,
10327daaab633a80be50863e6539e947db674090662Dianne Hackborn                    AppOpsManager.OP_WIFI_SCAN,
10415ab7758df616a27c28276ab97ddb2e2de6089f7Dianne Hackborn                    AppOpsManager.OP_NEIGHBORING_CELLS,
1054a06e4cc4370f5897f07f6314f25b37db759cf18David Christie                    AppOpsManager.OP_MONITOR_LOCATION,
1064a06e4cc4370f5897f07f6314f25b37db759cf18David Christie                    AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION},
10727daaab633a80be50863e6539e947db674090662Dianne Hackborn            new boolean[] { true,
10827daaab633a80be50863e6539e947db674090662Dianne Hackborn                    true,
10927daaab633a80be50863e6539e947db674090662Dianne Hackborn                    false,
11015ab7758df616a27c28276ab97ddb2e2de6089f7Dianne Hackborn                    false,
11127daaab633a80be50863e6539e947db674090662Dianne Hackborn                    false,
1124a06e4cc4370f5897f07f6314f25b37db759cf18David Christie                    false,
1134a06e4cc4370f5897f07f6314f25b37db759cf18David Christie                    false}
11418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            );
11518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
11618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    public static final OpsTemplate PERSONAL_TEMPLATE = new OpsTemplate(
11718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            new int[] { AppOpsManager.OP_READ_CONTACTS,
11818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    AppOpsManager.OP_WRITE_CONTACTS,
11918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    AppOpsManager.OP_READ_CALL_LOG,
1200dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                    AppOpsManager.OP_WRITE_CALL_LOG,
1210dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                    AppOpsManager.OP_READ_CALENDAR,
122782c3de338d6b4ac8280e0686b8a4b39c0e3f70fDianne Hackborn                    AppOpsManager.OP_WRITE_CALENDAR,
123782c3de338d6b4ac8280e0686b8a4b39c0e3f70fDianne Hackborn                    AppOpsManager.OP_READ_CLIPBOARD,
124782c3de338d6b4ac8280e0686b8a4b39c0e3f70fDianne Hackborn                    AppOpsManager.OP_WRITE_CLIPBOARD },
12527daaab633a80be50863e6539e947db674090662Dianne Hackborn            new boolean[] { true,
12627daaab633a80be50863e6539e947db674090662Dianne Hackborn                    true,
12727daaab633a80be50863e6539e947db674090662Dianne Hackborn                    true,
12827daaab633a80be50863e6539e947db674090662Dianne Hackborn                    true,
12927daaab633a80be50863e6539e947db674090662Dianne Hackborn                    true,
130782c3de338d6b4ac8280e0686b8a4b39c0e3f70fDianne Hackborn                    true,
131782c3de338d6b4ac8280e0686b8a4b39c0e3f70fDianne Hackborn                    false,
132782c3de338d6b4ac8280e0686b8a4b39c0e3f70fDianne Hackborn                    false }
13318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            );
13418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
135983378738761150d8ba649b4b1d74635881e61ecDianne Hackborn    public static final OpsTemplate MESSAGING_TEMPLATE = new OpsTemplate(
136983378738761150d8ba649b4b1d74635881e61ecDianne Hackborn            new int[] { AppOpsManager.OP_READ_SMS,
137983378738761150d8ba649b4b1d74635881e61ecDianne Hackborn                    AppOpsManager.OP_RECEIVE_SMS,
138983378738761150d8ba649b4b1d74635881e61ecDianne Hackborn                    AppOpsManager.OP_RECEIVE_EMERGECY_SMS,
139983378738761150d8ba649b4b1d74635881e61ecDianne Hackborn                    AppOpsManager.OP_RECEIVE_MMS,
140983378738761150d8ba649b4b1d74635881e61ecDianne Hackborn                    AppOpsManager.OP_RECEIVE_WAP_PUSH,
141983378738761150d8ba649b4b1d74635881e61ecDianne Hackborn                    AppOpsManager.OP_WRITE_SMS,
142983378738761150d8ba649b4b1d74635881e61ecDianne Hackborn                    AppOpsManager.OP_SEND_SMS,
143983378738761150d8ba649b4b1d74635881e61ecDianne Hackborn                    AppOpsManager.OP_READ_ICC_SMS,
144983378738761150d8ba649b4b1d74635881e61ecDianne Hackborn                    AppOpsManager.OP_WRITE_ICC_SMS },
145983378738761150d8ba649b4b1d74635881e61ecDianne Hackborn            new boolean[] { true,
146983378738761150d8ba649b4b1d74635881e61ecDianne Hackborn                    true,
147983378738761150d8ba649b4b1d74635881e61ecDianne Hackborn                    true,
148983378738761150d8ba649b4b1d74635881e61ecDianne Hackborn                    true,
149983378738761150d8ba649b4b1d74635881e61ecDianne Hackborn                    true,
150983378738761150d8ba649b4b1d74635881e61ecDianne Hackborn                    true,
151983378738761150d8ba649b4b1d74635881e61ecDianne Hackborn                    true,
152983378738761150d8ba649b4b1d74635881e61ecDianne Hackborn                    true,
153983378738761150d8ba649b4b1d74635881e61ecDianne Hackborn                    true }
154983378738761150d8ba649b4b1d74635881e61ecDianne Hackborn            );
155983378738761150d8ba649b4b1d74635881e61ecDianne Hackborn
1566e91babedac9983b10fdf2650de86386800017beDianne Hackborn    public static final OpsTemplate MEDIA_TEMPLATE = new OpsTemplate(
157df3f6d6c4722a7acc8189e47d0499aaf618969f9Daniel Sandler            new int[] { AppOpsManager.OP_VIBRATE,
1587ff56d331e1dfe133e734a36d191fc1d81b31e95Dianne Hackborn                    AppOpsManager.OP_CAMERA,
1597ff56d331e1dfe133e734a36d191fc1d81b31e95Dianne Hackborn                    AppOpsManager.OP_RECORD_AUDIO,
1606e91babedac9983b10fdf2650de86386800017beDianne Hackborn                    AppOpsManager.OP_PLAY_AUDIO,
1616e91babedac9983b10fdf2650de86386800017beDianne Hackborn                    AppOpsManager.OP_TAKE_MEDIA_BUTTONS,
1626e91babedac9983b10fdf2650de86386800017beDianne Hackborn                    AppOpsManager.OP_TAKE_AUDIO_FOCUS,
1636e91babedac9983b10fdf2650de86386800017beDianne Hackborn                    AppOpsManager.OP_AUDIO_MASTER_VOLUME,
1646e91babedac9983b10fdf2650de86386800017beDianne Hackborn                    AppOpsManager.OP_AUDIO_VOICE_VOLUME,
1656e91babedac9983b10fdf2650de86386800017beDianne Hackborn                    AppOpsManager.OP_AUDIO_RING_VOLUME,
1666e91babedac9983b10fdf2650de86386800017beDianne Hackborn                    AppOpsManager.OP_AUDIO_MEDIA_VOLUME,
1676e91babedac9983b10fdf2650de86386800017beDianne Hackborn                    AppOpsManager.OP_AUDIO_ALARM_VOLUME,
1686e91babedac9983b10fdf2650de86386800017beDianne Hackborn                    AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME,
1696e91babedac9983b10fdf2650de86386800017beDianne Hackborn                    AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME, },
17027daaab633a80be50863e6539e947db674090662Dianne Hackborn            new boolean[] { false,
171d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn                    true,
1727ff56d331e1dfe133e734a36d191fc1d81b31e95Dianne Hackborn                    true,
1736e91babedac9983b10fdf2650de86386800017beDianne Hackborn                    false,
1746e91babedac9983b10fdf2650de86386800017beDianne Hackborn                    false,
1756e91babedac9983b10fdf2650de86386800017beDianne Hackborn                    false,
1766e91babedac9983b10fdf2650de86386800017beDianne Hackborn                    false,
1776e91babedac9983b10fdf2650de86386800017beDianne Hackborn                    false,
1786e91babedac9983b10fdf2650de86386800017beDianne Hackborn                    false,
1796e91babedac9983b10fdf2650de86386800017beDianne Hackborn                    false,
1806e91babedac9983b10fdf2650de86386800017beDianne Hackborn                    false,
1816e91babedac9983b10fdf2650de86386800017beDianne Hackborn                    false,
1826e91babedac9983b10fdf2650de86386800017beDianne Hackborn                    false }
1836e91babedac9983b10fdf2650de86386800017beDianne Hackborn            );
1846e91babedac9983b10fdf2650de86386800017beDianne Hackborn
1856e91babedac9983b10fdf2650de86386800017beDianne Hackborn    public static final OpsTemplate DEVICE_TEMPLATE = new OpsTemplate(
1866e91babedac9983b10fdf2650de86386800017beDianne Hackborn            new int[] { AppOpsManager.OP_POST_NOTIFICATION,
1876e91babedac9983b10fdf2650de86386800017beDianne Hackborn                    AppOpsManager.OP_ACCESS_NOTIFICATIONS,
1886e91babedac9983b10fdf2650de86386800017beDianne Hackborn                    AppOpsManager.OP_CALL_PHONE,
1896e91babedac9983b10fdf2650de86386800017beDianne Hackborn                    AppOpsManager.OP_WRITE_SETTINGS,
190ec74da60cda5d0d7d1901e20a5a7806ef4cf387fDianne Hackborn                    AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
191ec74da60cda5d0d7d1901e20a5a7806ef4cf387fDianne Hackborn                    AppOpsManager.OP_WAKE_LOCK },
1926e91babedac9983b10fdf2650de86386800017beDianne Hackborn            new boolean[] { false,
1937ff56d331e1dfe133e734a36d191fc1d81b31e95Dianne Hackborn                    true,
1947ff56d331e1dfe133e734a36d191fc1d81b31e95Dianne Hackborn                    true,
1957ff56d331e1dfe133e734a36d191fc1d81b31e95Dianne Hackborn                    true,
196ec74da60cda5d0d7d1901e20a5a7806ef4cf387fDianne Hackborn                    true,
197ec74da60cda5d0d7d1901e20a5a7806ef4cf387fDianne Hackborn                    true,  }
19818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            );
19918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
2000dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn    public static final OpsTemplate[] ALL_TEMPLATES = new OpsTemplate[] {
2016e91babedac9983b10fdf2650de86386800017beDianne Hackborn            LOCATION_TEMPLATE, PERSONAL_TEMPLATE, MESSAGING_TEMPLATE,
2026e91babedac9983b10fdf2650de86386800017beDianne Hackborn            MEDIA_TEMPLATE, DEVICE_TEMPLATE
2030dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn    };
2040dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn
20518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    /**
20618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn     * This class holds the per-item data in our Loader.
20718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn     */
20818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    public static class AppEntry {
20918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        private final AppOpsState mState;
21018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        private final ApplicationInfo mInfo;
21118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        private final File mApkFile;
2120dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        private final SparseArray<AppOpsManager.OpEntry> mOps
2130dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                = new SparseArray<AppOpsManager.OpEntry>();
21427daaab633a80be50863e6539e947db674090662Dianne Hackborn        private final SparseArray<AppOpEntry> mOpSwitches
21527daaab633a80be50863e6539e947db674090662Dianne Hackborn                = new SparseArray<AppOpEntry>();
21618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        private String mLabel;
21718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        private Drawable mIcon;
21818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        private boolean mMounted;
21918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
22018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        public AppEntry(AppOpsState state, ApplicationInfo info) {
22118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            mState = state;
22218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            mInfo = info;
22318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            mApkFile = new File(info.sourceDir);
22418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
22518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
22627daaab633a80be50863e6539e947db674090662Dianne Hackborn        public void addOp(AppOpEntry entry, AppOpsManager.OpEntry op) {
2270dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            mOps.put(op.getOp(), op);
22827daaab633a80be50863e6539e947db674090662Dianne Hackborn            mOpSwitches.put(AppOpsManager.opToSwitch(op.getOp()), entry);
2290dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        }
2300dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn
2310dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        public boolean hasOp(int op) {
2320dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            return mOps.indexOfKey(op) >= 0;
2330dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        }
2340dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn
23527daaab633a80be50863e6539e947db674090662Dianne Hackborn        public AppOpEntry getOpSwitch(int op) {
23627daaab633a80be50863e6539e947db674090662Dianne Hackborn            return mOpSwitches.get(AppOpsManager.opToSwitch(op));
23727daaab633a80be50863e6539e947db674090662Dianne Hackborn        }
23827daaab633a80be50863e6539e947db674090662Dianne Hackborn
23918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        public ApplicationInfo getApplicationInfo() {
24018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            return mInfo;
24118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
24218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
24318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        public String getLabel() {
24418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            return mLabel;
24518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
24618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
24718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        public Drawable getIcon() {
24818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            if (mIcon == null) {
24918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                if (mApkFile.exists()) {
25018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    mIcon = mInfo.loadIcon(mState.mPm);
25118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    return mIcon;
25218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                } else {
25318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    mMounted = false;
25418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                }
25518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            } else if (!mMounted) {
25618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                // If the app wasn't mounted but is now mounted, reload
25718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                // its icon.
25818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                if (mApkFile.exists()) {
25918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    mMounted = true;
26018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    mIcon = mInfo.loadIcon(mState.mPm);
26118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    return mIcon;
26218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                }
26318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            } else {
26418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                return mIcon;
26518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            }
26618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
26718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            return mState.mContext.getResources().getDrawable(
26818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    android.R.drawable.sym_def_app_icon);
26918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
27018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
27118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        @Override public String toString() {
27218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            return mLabel;
27318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
27418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
27518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        void loadLabel(Context context) {
27618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            if (mLabel == null || !mMounted) {
27718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                if (!mApkFile.exists()) {
27818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    mMounted = false;
27918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    mLabel = mInfo.packageName;
28018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                } else {
28118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    mMounted = true;
28218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    CharSequence label = mInfo.loadLabel(context.getPackageManager());
28318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    mLabel = label != null ? label.toString() : mInfo.packageName;
28418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                }
28518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            }
28618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
28718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    }
28818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
28918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    /**
29018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn     * This class holds the per-item data in our Loader.
29118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn     */
29218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    public static class AppOpEntry {
29318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        private final AppOpsManager.PackageOps mPkgOps;
29418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        private final ArrayList<AppOpsManager.OpEntry> mOps
29518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                = new ArrayList<AppOpsManager.OpEntry>();
2968b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn        private final ArrayList<AppOpsManager.OpEntry> mSwitchOps
29727daaab633a80be50863e6539e947db674090662Dianne Hackborn                = new ArrayList<AppOpsManager.OpEntry>();
29818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        private final AppEntry mApp;
299d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn        private final int mSwitchOrder;
30018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
301d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn        public AppOpEntry(AppOpsManager.PackageOps pkg, AppOpsManager.OpEntry op, AppEntry app,
302d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn                int switchOrder) {
30318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            mPkgOps = pkg;
30418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            mApp = app;
305d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn            mSwitchOrder = switchOrder;
30627daaab633a80be50863e6539e947db674090662Dianne Hackborn            mApp.addOp(this, op);
3070dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            mOps.add(op);
3088b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn            mSwitchOps.add(op);
30918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
31018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
31127daaab633a80be50863e6539e947db674090662Dianne Hackborn        private static void addOp(ArrayList<AppOpsManager.OpEntry> list, AppOpsManager.OpEntry op) {
31227daaab633a80be50863e6539e947db674090662Dianne Hackborn            for (int i=0; i<list.size(); i++) {
31327daaab633a80be50863e6539e947db674090662Dianne Hackborn                AppOpsManager.OpEntry pos = list.get(i);
31418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                if (pos.isRunning() != op.isRunning()) {
31518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    if (op.isRunning()) {
31627daaab633a80be50863e6539e947db674090662Dianne Hackborn                        list.add(i, op);
31718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                        return;
31818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    }
3190dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                    continue;
32018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                }
3210dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                if (pos.getTime() < op.getTime()) {
32227daaab633a80be50863e6539e947db674090662Dianne Hackborn                    list.add(i, op);
32318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    return;
32418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                }
32518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            }
32627daaab633a80be50863e6539e947db674090662Dianne Hackborn            list.add(op);
32727daaab633a80be50863e6539e947db674090662Dianne Hackborn        }
32827daaab633a80be50863e6539e947db674090662Dianne Hackborn
3298b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn        public void addOp(AppOpsManager.OpEntry op) {
33027daaab633a80be50863e6539e947db674090662Dianne Hackborn            mApp.addOp(this, op);
33127daaab633a80be50863e6539e947db674090662Dianne Hackborn            addOp(mOps, op);
3328b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn            if (mApp.getOpSwitch(AppOpsManager.opToSwitch(op.getOp())) == null) {
3338b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn                addOp(mSwitchOps, op);
33427daaab633a80be50863e6539e947db674090662Dianne Hackborn            }
33518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
33618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
33718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        public AppEntry getAppEntry() {
33818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            return mApp;
33918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
34018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
341d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn        public int getSwitchOrder() {
342d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn            return mSwitchOrder;
343d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn        }
344d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn
34518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        public AppOpsManager.PackageOps getPackageOps() {
34618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            return mPkgOps;
34718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
34818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
34918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        public int getNumOpEntry() {
35018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            return mOps.size();
35118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
35218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
35318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        public AppOpsManager.OpEntry getOpEntry(int pos) {
35418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            return mOps.get(pos);
35518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
35618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
3578b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn        private CharSequence getCombinedText(ArrayList<AppOpsManager.OpEntry> ops,
3588b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn                CharSequence[] items) {
35927daaab633a80be50863e6539e947db674090662Dianne Hackborn            if (ops.size() == 1) {
3608b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn                return items[ops.get(0).getOp()];
36118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            } else {
36218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                StringBuilder builder = new StringBuilder();
36327daaab633a80be50863e6539e947db674090662Dianne Hackborn                for (int i=0; i<ops.size(); i++) {
36418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    if (i > 0) {
36518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                        builder.append(", ");
36618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    }
3678b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn                    builder.append(items[ops.get(i).getOp()]);
36818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                }
36918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                return builder.toString();
37018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            }
37118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
37218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
3738b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn        public CharSequence getSummaryText(AppOpsState state) {
3748b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn            return getCombinedText(mOps, state.mOpSummaries);
37527daaab633a80be50863e6539e947db674090662Dianne Hackborn        }
37627daaab633a80be50863e6539e947db674090662Dianne Hackborn
3778b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn        public CharSequence getSwitchText(AppOpsState state) {
3788b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn            if (mSwitchOps.size() > 0) {
3798b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn                return getCombinedText(mSwitchOps, state.mOpLabels);
38027daaab633a80be50863e6539e947db674090662Dianne Hackborn            } else {
3818b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn                return getCombinedText(mOps, state.mOpLabels);
38227daaab633a80be50863e6539e947db674090662Dianne Hackborn            }
38327daaab633a80be50863e6539e947db674090662Dianne Hackborn        }
38427daaab633a80be50863e6539e947db674090662Dianne Hackborn
3858b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn        public CharSequence getTimeText(Resources res, boolean showEmptyText) {
38618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            if (isRunning()) {
38718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                return res.getText(R.string.app_ops_running);
38818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            }
38918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            if (getTime() > 0) {
39018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                return DateUtils.getRelativeTimeSpanString(getTime(),
39118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                        System.currentTimeMillis(),
39218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                        DateUtils.MINUTE_IN_MILLIS,
39318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                        DateUtils.FORMAT_ABBREV_RELATIVE);
39418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            }
3958b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn            return showEmptyText ? res.getText(R.string.app_ops_never_used) : "";
39618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
39718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
39818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        public boolean isRunning() {
39918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            return mOps.get(0).isRunning();
40018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
40118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
40218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        public long getTime() {
40318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            return mOps.get(0).getTime();
40418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
40518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
40618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        @Override public String toString() {
40718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            return mApp.getLabel();
40818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
40918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    }
41018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
41118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    /**
41218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn     * Perform alphabetical comparison of application entry objects.
41318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn     */
41418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    public static final Comparator<AppOpEntry> APP_OP_COMPARATOR = new Comparator<AppOpEntry>() {
41518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        private final Collator sCollator = Collator.getInstance();
41618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        @Override
41718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        public int compare(AppOpEntry object1, AppOpEntry object2) {
418d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn            if (object1.getSwitchOrder() != object2.getSwitchOrder()) {
419d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn                return object1.getSwitchOrder() < object2.getSwitchOrder() ? -1 : 1;
420d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn            }
42118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            if (object1.isRunning() != object2.isRunning()) {
42218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                // Currently running ops go first.
42318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                return object1.isRunning() ? -1 : 1;
42418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            }
42518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            if (object1.getTime() != object2.getTime()) {
42618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                // More recent times go first.
42718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                return object1.getTime() > object2.getTime() ? -1 : 1;
42818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            }
42918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            return sCollator.compare(object1.getAppEntry().getLabel(),
43018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    object2.getAppEntry().getLabel());
43118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
43218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    };
43318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
43418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    private void addOp(List<AppOpEntry> entries, AppOpsManager.PackageOps pkgOps,
435d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn            AppEntry appEntry, AppOpsManager.OpEntry opEntry, boolean allowMerge, int switchOrder) {
43627daaab633a80be50863e6539e947db674090662Dianne Hackborn        if (allowMerge && entries.size() > 0) {
43718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            AppOpEntry last = entries.get(entries.size()-1);
43818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            if (last.getAppEntry() == appEntry) {
43918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                boolean lastExe = last.getTime() != 0;
44018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                boolean entryExe = opEntry.getTime() != 0;
44118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                if (lastExe == entryExe) {
4420dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                    if (DEBUG) Log.d(TAG, "Add op " + opEntry.getOp() + " to package "
4430dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                            + pkgOps.getPackageName() + ": append to " + last);
4448b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn                    last.addOp(opEntry);
44518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    return;
44618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                }
44718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            }
44818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
44927daaab633a80be50863e6539e947db674090662Dianne Hackborn        AppOpEntry entry = appEntry.getOpSwitch(opEntry.getOp());
45027daaab633a80be50863e6539e947db674090662Dianne Hackborn        if (entry != null) {
4518b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn            entry.addOp(opEntry);
45227daaab633a80be50863e6539e947db674090662Dianne Hackborn            return;
45327daaab633a80be50863e6539e947db674090662Dianne Hackborn        }
454d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn        entry = new AppOpEntry(pkgOps, opEntry, appEntry, switchOrder);
4550dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        if (DEBUG) Log.d(TAG, "Add op " + opEntry.getOp() + " to package "
4560dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                + pkgOps.getPackageName() + ": making new " + entry);
45718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        entries.add(entry);
45818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    }
45918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
46018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    public List<AppOpEntry> buildState(OpsTemplate tpl) {
46118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        return buildState(tpl, 0, null);
46218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    }
46318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
4640dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn    private AppEntry getAppEntry(final Context context, final HashMap<String, AppEntry> appEntries,
4650dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            final String packageName, ApplicationInfo appInfo) {
4660dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        AppEntry appEntry = appEntries.get(packageName);
4670dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        if (appEntry == null) {
4680dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            if (appInfo == null) {
4690dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                try {
4700dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                    appInfo = mPm.getApplicationInfo(packageName,
4710dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                            PackageManager.GET_DISABLED_COMPONENTS
4720dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                            | PackageManager.GET_UNINSTALLED_PACKAGES);
4730dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                } catch (PackageManager.NameNotFoundException e) {
4740dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                    Log.w(TAG, "Unable to find info for package " + packageName);
4750dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                    return null;
4760dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                }
4770dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            }
4780dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            appEntry = new AppEntry(this, appInfo);
4790dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            appEntry.loadLabel(context);
4800dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            appEntries.put(packageName, appEntry);
4810dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        }
4820dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        return appEntry;
4830dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn    }
4840dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn
48518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    public List<AppOpEntry> buildState(OpsTemplate tpl, int uid, String packageName) {
48618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        final Context context = mContext;
48718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
48818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        final HashMap<String, AppEntry> appEntries = new HashMap<String, AppEntry>();
48927daaab633a80be50863e6539e947db674090662Dianne Hackborn        final List<AppOpEntry> entries = new ArrayList<AppOpEntry>();
4900dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn
49127daaab633a80be50863e6539e947db674090662Dianne Hackborn        final ArrayList<String> perms = new ArrayList<String>();
49227daaab633a80be50863e6539e947db674090662Dianne Hackborn        final ArrayList<Integer> permOps = new ArrayList<Integer>();
493d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn        final int[] opToOrder = new int[AppOpsManager._NUM_OP];
4940dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        for (int i=0; i<tpl.ops.length; i++) {
49527daaab633a80be50863e6539e947db674090662Dianne Hackborn            if (tpl.showPerms[i]) {
49627daaab633a80be50863e6539e947db674090662Dianne Hackborn                String perm = AppOpsManager.opToPermission(tpl.ops[i]);
49727daaab633a80be50863e6539e947db674090662Dianne Hackborn                if (perm != null && !perms.contains(perm)) {
49827daaab633a80be50863e6539e947db674090662Dianne Hackborn                    perms.add(perm);
49927daaab633a80be50863e6539e947db674090662Dianne Hackborn                    permOps.add(tpl.ops[i]);
500d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn                    opToOrder[tpl.ops[i]] = i;
50127daaab633a80be50863e6539e947db674090662Dianne Hackborn                }
5020dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            }
5030dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        }
50418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
50518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        List<AppOpsManager.PackageOps> pkgs;
50618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        if (packageName != null) {
50718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            pkgs = mAppOps.getOpsForPackage(uid, packageName, tpl.ops);
50818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        } else {
50918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            pkgs = mAppOps.getPackagesForOps(tpl.ops);
51018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
5110dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn
5120dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        if (pkgs != null) {
5130dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            for (int i=0; i<pkgs.size(); i++) {
5140dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                AppOpsManager.PackageOps pkgOps = pkgs.get(i);
5150dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                AppEntry appEntry = getAppEntry(context, appEntries, pkgOps.getPackageName(), null);
5160dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                if (appEntry == null) {
5170dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                    continue;
5180dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                }
5190dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                for (int j=0; j<pkgOps.getOps().size(); j++) {
5200dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                    AppOpsManager.OpEntry opEntry = pkgOps.getOps().get(j);
521d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn                    addOp(entries, pkgOps, appEntry, opEntry, packageName == null,
522d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn                            packageName == null ? 0 : opToOrder[opEntry.getOp()]);
52318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                }
52418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            }
52518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
52618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
5270dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        List<PackageInfo> apps;
5280dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        if (packageName != null) {
5290dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            apps = new ArrayList<PackageInfo>();
5300dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            try {
5310dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                PackageInfo pi = mPm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS);
5320dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                apps.add(pi);
5330dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            } catch (NameNotFoundException e) {
53418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            }
5350dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        } else {
5360dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            String[] permsArray = new String[perms.size()];
5370dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            perms.toArray(permsArray);
5380dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            apps = mPm.getPackagesHoldingPermissions(permsArray, 0);
5390dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        }
5400dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        for (int i=0; i<apps.size(); i++) {
5410dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            PackageInfo appInfo = apps.get(i);
5420dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            AppEntry appEntry = getAppEntry(context, appEntries, appInfo.packageName,
5430dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                    appInfo.applicationInfo);
5440dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            if (appEntry == null) {
5450dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                continue;
5460dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            }
5470dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            List<AppOpsManager.OpEntry> dummyOps = null;
5480dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            AppOpsManager.PackageOps pkgOps = null;
5497d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler            if (appInfo.requestedPermissions != null) {
5507d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                for (int j=0; j<appInfo.requestedPermissions.length; j++) {
5517d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                    if (appInfo.requestedPermissionsFlags != null) {
5527d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                        if ((appInfo.requestedPermissionsFlags[j]
5537d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                                & PackageInfo.REQUESTED_PERMISSION_GRANTED) == 0) {
5547d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                            if (DEBUG) Log.d(TAG, "Pkg " + appInfo.packageName + " perm "
5557d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                                    + appInfo.requestedPermissions[j] + " not granted; skipping");
55667e72d9e8a2146ede95c06cac60c2100ad59a33bDanny Baumann                            continue;
5577d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                        }
55818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    }
5597d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                    if (DEBUG) Log.d(TAG, "Pkg " + appInfo.packageName + ": requested perm "
5607d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                            + appInfo.requestedPermissions[j]);
5617d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                    for (int k=0; k<perms.size(); k++) {
5627d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                        if (!perms.get(k).equals(appInfo.requestedPermissions[j])) {
5637d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                            continue;
5647d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                        }
5657d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                        if (DEBUG) Log.d(TAG, "Pkg " + appInfo.packageName + " perm " + perms.get(k)
5667d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                                + " has op " + permOps.get(k) + ": " + appEntry.hasOp(permOps.get(k)));
5677d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                        if (appEntry.hasOp(permOps.get(k))) {
5687d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                            continue;
5697d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                        }
5707d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                        if (dummyOps == null) {
5717d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                            dummyOps = new ArrayList<AppOpsManager.OpEntry>();
5727d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                            pkgOps = new AppOpsManager.PackageOps(
5737d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                                    appInfo.packageName, appInfo.applicationInfo.uid, dummyOps);
5747d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler
5757d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                        }
5767d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                        AppOpsManager.OpEntry opEntry = new AppOpsManager.OpEntry(
5777d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                                permOps.get(k), AppOpsManager.MODE_ALLOWED, 0, 0, 0);
5787d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                        dummyOps.add(opEntry);
579d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn                        addOp(entries, pkgOps, appEntry, opEntry, packageName == null,
580d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn                                packageName == null ? 0 : opToOrder[opEntry.getOp()]);
5810dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                    }
5820dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                }
58318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            }
58418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
58518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
58618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        // Sort the list.
58718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        Collections.sort(entries, APP_OP_COMPARATOR);
58818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
58918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        // Done!
59018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        return entries;
59118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    }
59218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn}
593