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;
300dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackbornimport android.util.Log;
310dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackbornimport android.util.SparseArray;
3239b467482d1bf256a111c757e9b7621c6f523271Jason Monk
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,
106bdf28e40251772a35f776af9fd1a4b903f0f9771Michael Wright                    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,
113bdf28e40251772a35f776af9fd1a4b903f0f9771Michael Wright                    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,
1694241d0b8db1c4352956ce877272a9ebe1770ad01Emily Bernier                    AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME,
1704241d0b8db1c4352956ce877272a9ebe1770ad01Emily Bernier                    AppOpsManager.OP_MUTE_MICROPHONE},
17127daaab633a80be50863e6539e947db674090662Dianne Hackborn            new boolean[] { false,
172d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn                    true,
1737ff56d331e1dfe133e734a36d191fc1d81b31e95Dianne Hackborn                    true,
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,
183f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn                    false,
1846e91babedac9983b10fdf2650de86386800017beDianne Hackborn                    false }
1856e91babedac9983b10fdf2650de86386800017beDianne Hackborn            );
1866e91babedac9983b10fdf2650de86386800017beDianne Hackborn
1876e91babedac9983b10fdf2650de86386800017beDianne Hackborn    public static final OpsTemplate DEVICE_TEMPLATE = new OpsTemplate(
1886e91babedac9983b10fdf2650de86386800017beDianne Hackborn            new int[] { AppOpsManager.OP_POST_NOTIFICATION,
1896e91babedac9983b10fdf2650de86386800017beDianne Hackborn                    AppOpsManager.OP_ACCESS_NOTIFICATIONS,
1906e91babedac9983b10fdf2650de86386800017beDianne Hackborn                    AppOpsManager.OP_CALL_PHONE,
1916e91babedac9983b10fdf2650de86386800017beDianne Hackborn                    AppOpsManager.OP_WRITE_SETTINGS,
192ec74da60cda5d0d7d1901e20a5a7806ef4cf387fDianne Hackborn                    AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
193bdf28e40251772a35f776af9fd1a4b903f0f9771Michael Wright                    AppOpsManager.OP_WAKE_LOCK,
19490b3b211efda80535ac2981032f66e117ffeb221Jeff Davidson                    AppOpsManager.OP_PROJECT_MEDIA,
1957781ef68703995c6724eb618c8c0c3eb10cb2a73Dianne Hackborn                    AppOpsManager.OP_ACTIVATE_VPN,
1967781ef68703995c6724eb618c8c0c3eb10cb2a73Dianne Hackborn                    AppOpsManager.OP_ASSIST_STRUCTURE,
1977781ef68703995c6724eb618c8c0c3eb10cb2a73Dianne Hackborn                    AppOpsManager.OP_ASSIST_SCREENSHOT},
1986e91babedac9983b10fdf2650de86386800017beDianne Hackborn            new boolean[] { false,
1997ff56d331e1dfe133e734a36d191fc1d81b31e95Dianne Hackborn                    true,
2007ff56d331e1dfe133e734a36d191fc1d81b31e95Dianne Hackborn                    true,
2017ff56d331e1dfe133e734a36d191fc1d81b31e95Dianne Hackborn                    true,
202ec74da60cda5d0d7d1901e20a5a7806ef4cf387fDianne Hackborn                    true,
203bdf28e40251772a35f776af9fd1a4b903f0f9771Michael Wright                    true,
20490b3b211efda80535ac2981032f66e117ffeb221Jeff Davidson                    false,
2057781ef68703995c6724eb618c8c0c3eb10cb2a73Dianne Hackborn                    false,
2067781ef68703995c6724eb618c8c0c3eb10cb2a73Dianne Hackborn                    false,
2077781ef68703995c6724eb618c8c0c3eb10cb2a73Dianne Hackborn                    false }
20818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            );
20918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
210f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn    public static final OpsTemplate RUN_IN_BACKGROUND_TEMPLATE = new OpsTemplate(
211f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn            new int[] { AppOpsManager.OP_RUN_IN_BACKGROUND },
212f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn            new boolean[] { false }
213f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn            );
214f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn
2150dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn    public static final OpsTemplate[] ALL_TEMPLATES = new OpsTemplate[] {
2166e91babedac9983b10fdf2650de86386800017beDianne Hackborn            LOCATION_TEMPLATE, PERSONAL_TEMPLATE, MESSAGING_TEMPLATE,
217f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn            MEDIA_TEMPLATE, DEVICE_TEMPLATE, RUN_IN_BACKGROUND_TEMPLATE
2180dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn    };
2190dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn
22018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    /**
22118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn     * This class holds the per-item data in our Loader.
22218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn     */
22318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    public static class AppEntry {
22418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        private final AppOpsState mState;
22518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        private final ApplicationInfo mInfo;
22618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        private final File mApkFile;
2270dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        private final SparseArray<AppOpsManager.OpEntry> mOps
2280dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                = new SparseArray<AppOpsManager.OpEntry>();
22927daaab633a80be50863e6539e947db674090662Dianne Hackborn        private final SparseArray<AppOpEntry> mOpSwitches
23027daaab633a80be50863e6539e947db674090662Dianne Hackborn                = new SparseArray<AppOpEntry>();
23118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        private String mLabel;
23218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        private Drawable mIcon;
23318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        private boolean mMounted;
23418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
23518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        public AppEntry(AppOpsState state, ApplicationInfo info) {
23618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            mState = state;
23718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            mInfo = info;
23818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            mApkFile = new File(info.sourceDir);
23918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
24018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
24127daaab633a80be50863e6539e947db674090662Dianne Hackborn        public void addOp(AppOpEntry entry, AppOpsManager.OpEntry op) {
2420dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            mOps.put(op.getOp(), op);
24327daaab633a80be50863e6539e947db674090662Dianne Hackborn            mOpSwitches.put(AppOpsManager.opToSwitch(op.getOp()), entry);
2440dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        }
2450dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn
2460dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        public boolean hasOp(int op) {
2470dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            return mOps.indexOfKey(op) >= 0;
2480dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        }
2490dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn
25027daaab633a80be50863e6539e947db674090662Dianne Hackborn        public AppOpEntry getOpSwitch(int op) {
25127daaab633a80be50863e6539e947db674090662Dianne Hackborn            return mOpSwitches.get(AppOpsManager.opToSwitch(op));
25227daaab633a80be50863e6539e947db674090662Dianne Hackborn        }
25327daaab633a80be50863e6539e947db674090662Dianne Hackborn
25418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        public ApplicationInfo getApplicationInfo() {
25518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            return mInfo;
25618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
25718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
25818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        public String getLabel() {
25918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            return mLabel;
26018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
26118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
26218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        public Drawable getIcon() {
26318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            if (mIcon == null) {
26418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                if (mApkFile.exists()) {
26518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    mIcon = mInfo.loadIcon(mState.mPm);
26618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    return mIcon;
26718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                } else {
26818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    mMounted = false;
26918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                }
27018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            } else if (!mMounted) {
27118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                // If the app wasn't mounted but is now mounted, reload
27218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                // its icon.
27318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                if (mApkFile.exists()) {
27418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    mMounted = true;
27518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    mIcon = mInfo.loadIcon(mState.mPm);
27618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    return mIcon;
27718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                }
27818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            } else {
27918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                return mIcon;
28018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            }
28118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
2820ba89bd54c4b44b3803342da10b0c08b0bf76ad4Alan Viverette            return mState.mContext.getDrawable(
28318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    android.R.drawable.sym_def_app_icon);
28418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
28518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
28618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        @Override public String toString() {
28718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            return mLabel;
28818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
28918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
29018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        void loadLabel(Context context) {
29118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            if (mLabel == null || !mMounted) {
29218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                if (!mApkFile.exists()) {
29318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    mMounted = false;
29418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    mLabel = mInfo.packageName;
29518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                } else {
29618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    mMounted = true;
29718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    CharSequence label = mInfo.loadLabel(context.getPackageManager());
29818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    mLabel = label != null ? label.toString() : mInfo.packageName;
29918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                }
30018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            }
30118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
30218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    }
30318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
30418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    /**
30518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn     * This class holds the per-item data in our Loader.
30618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn     */
30718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    public static class AppOpEntry {
30818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        private final AppOpsManager.PackageOps mPkgOps;
30918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        private final ArrayList<AppOpsManager.OpEntry> mOps
31018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                = new ArrayList<AppOpsManager.OpEntry>();
3118b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn        private final ArrayList<AppOpsManager.OpEntry> mSwitchOps
31227daaab633a80be50863e6539e947db674090662Dianne Hackborn                = new ArrayList<AppOpsManager.OpEntry>();
31318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        private final AppEntry mApp;
314d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn        private final int mSwitchOrder;
315f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn        private int mOverriddenPrimaryMode = -1;
31618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
317d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn        public AppOpEntry(AppOpsManager.PackageOps pkg, AppOpsManager.OpEntry op, AppEntry app,
318d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn                int switchOrder) {
31918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            mPkgOps = pkg;
32018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            mApp = app;
321d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn            mSwitchOrder = switchOrder;
32227daaab633a80be50863e6539e947db674090662Dianne Hackborn            mApp.addOp(this, op);
3230dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            mOps.add(op);
3248b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn            mSwitchOps.add(op);
32518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
32618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
32727daaab633a80be50863e6539e947db674090662Dianne Hackborn        private static void addOp(ArrayList<AppOpsManager.OpEntry> list, AppOpsManager.OpEntry op) {
32827daaab633a80be50863e6539e947db674090662Dianne Hackborn            for (int i=0; i<list.size(); i++) {
32927daaab633a80be50863e6539e947db674090662Dianne Hackborn                AppOpsManager.OpEntry pos = list.get(i);
33018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                if (pos.isRunning() != op.isRunning()) {
33118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    if (op.isRunning()) {
33227daaab633a80be50863e6539e947db674090662Dianne Hackborn                        list.add(i, op);
33318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                        return;
33418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    }
3350dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                    continue;
33618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                }
3370dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                if (pos.getTime() < op.getTime()) {
33827daaab633a80be50863e6539e947db674090662Dianne Hackborn                    list.add(i, op);
33918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    return;
34018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                }
34118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            }
34227daaab633a80be50863e6539e947db674090662Dianne Hackborn            list.add(op);
34327daaab633a80be50863e6539e947db674090662Dianne Hackborn        }
34427daaab633a80be50863e6539e947db674090662Dianne Hackborn
3458b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn        public void addOp(AppOpsManager.OpEntry op) {
34627daaab633a80be50863e6539e947db674090662Dianne Hackborn            mApp.addOp(this, op);
34727daaab633a80be50863e6539e947db674090662Dianne Hackborn            addOp(mOps, op);
3488b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn            if (mApp.getOpSwitch(AppOpsManager.opToSwitch(op.getOp())) == null) {
3498b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn                addOp(mSwitchOps, op);
35027daaab633a80be50863e6539e947db674090662Dianne Hackborn            }
35118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
35218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
35318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        public AppEntry getAppEntry() {
35418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            return mApp;
35518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
35618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
357d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn        public int getSwitchOrder() {
358d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn            return mSwitchOrder;
359d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn        }
360d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn
36118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        public AppOpsManager.PackageOps getPackageOps() {
36218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            return mPkgOps;
36318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
36418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
36518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        public int getNumOpEntry() {
36618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            return mOps.size();
36718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
36818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
36918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        public AppOpsManager.OpEntry getOpEntry(int pos) {
37018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            return mOps.get(pos);
37118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
37218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
373f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn        public int getPrimaryOpMode() {
374f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn            return mOverriddenPrimaryMode >= 0 ? mOverriddenPrimaryMode : mOps.get(0).getMode();
375f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn        }
376f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn
377f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn        public void overridePrimaryOpMode(int mode) {
378f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn            mOverriddenPrimaryMode = mode;
379f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn        }
380f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn
3818b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn        private CharSequence getCombinedText(ArrayList<AppOpsManager.OpEntry> ops,
3828b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn                CharSequence[] items) {
38327daaab633a80be50863e6539e947db674090662Dianne Hackborn            if (ops.size() == 1) {
3848b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn                return items[ops.get(0).getOp()];
38518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            } else {
38618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                StringBuilder builder = new StringBuilder();
38727daaab633a80be50863e6539e947db674090662Dianne Hackborn                for (int i=0; i<ops.size(); i++) {
38818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    if (i > 0) {
38918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                        builder.append(", ");
39018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    }
3918b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn                    builder.append(items[ops.get(i).getOp()]);
39218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                }
39318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                return builder.toString();
39418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            }
39518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
39618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
3978b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn        public CharSequence getSummaryText(AppOpsState state) {
3988b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn            return getCombinedText(mOps, state.mOpSummaries);
39927daaab633a80be50863e6539e947db674090662Dianne Hackborn        }
40027daaab633a80be50863e6539e947db674090662Dianne Hackborn
4018b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn        public CharSequence getSwitchText(AppOpsState state) {
4028b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn            if (mSwitchOps.size() > 0) {
4038b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn                return getCombinedText(mSwitchOps, state.mOpLabels);
40427daaab633a80be50863e6539e947db674090662Dianne Hackborn            } else {
4058b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn                return getCombinedText(mOps, state.mOpLabels);
40627daaab633a80be50863e6539e947db674090662Dianne Hackborn            }
40727daaab633a80be50863e6539e947db674090662Dianne Hackborn        }
40827daaab633a80be50863e6539e947db674090662Dianne Hackborn
4098b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn        public CharSequence getTimeText(Resources res, boolean showEmptyText) {
41018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            if (isRunning()) {
41118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                return res.getText(R.string.app_ops_running);
41218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            }
41318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            if (getTime() > 0) {
41418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                return DateUtils.getRelativeTimeSpanString(getTime(),
41518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                        System.currentTimeMillis(),
41618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                        DateUtils.MINUTE_IN_MILLIS,
41718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                        DateUtils.FORMAT_ABBREV_RELATIVE);
41818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            }
4198b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn            return showEmptyText ? res.getText(R.string.app_ops_never_used) : "";
42018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
42118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
42218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        public boolean isRunning() {
42318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            return mOps.get(0).isRunning();
42418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
42518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
42618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        public long getTime() {
42718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            return mOps.get(0).getTime();
42818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
42918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
43018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        @Override public String toString() {
43118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            return mApp.getLabel();
43218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
43318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    }
43418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
43518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    /**
436f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn     * Perform app op state comparison of application entry objects.
43718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn     */
438f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn    public static final Comparator<AppOpEntry> RECENCY_COMPARATOR = new Comparator<AppOpEntry>() {
43918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        private final Collator sCollator = Collator.getInstance();
44018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        @Override
44118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        public int compare(AppOpEntry object1, AppOpEntry object2) {
442d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn            if (object1.getSwitchOrder() != object2.getSwitchOrder()) {
443d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn                return object1.getSwitchOrder() < object2.getSwitchOrder() ? -1 : 1;
444d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn            }
44518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            if (object1.isRunning() != object2.isRunning()) {
44618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                // Currently running ops go first.
44718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                return object1.isRunning() ? -1 : 1;
44818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            }
44918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            if (object1.getTime() != object2.getTime()) {
45018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                // More recent times go first.
45118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                return object1.getTime() > object2.getTime() ? -1 : 1;
45218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            }
45318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            return sCollator.compare(object1.getAppEntry().getLabel(),
45418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    object2.getAppEntry().getLabel());
45518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
45618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    };
45718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
458f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn    /**
459f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn     * Perform alphabetical comparison of application entry objects.
460f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn     */
461f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn    public static final Comparator<AppOpEntry> LABEL_COMPARATOR = new Comparator<AppOpEntry>() {
462f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn        private final Collator sCollator = Collator.getInstance();
463f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn        @Override
464f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn        public int compare(AppOpEntry object1, AppOpEntry object2) {
465f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn            return sCollator.compare(object1.getAppEntry().getLabel(),
466f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn                    object2.getAppEntry().getLabel());
467f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn        }
468f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn    };
469f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn
47018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    private void addOp(List<AppOpEntry> entries, AppOpsManager.PackageOps pkgOps,
471d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn            AppEntry appEntry, AppOpsManager.OpEntry opEntry, boolean allowMerge, int switchOrder) {
47227daaab633a80be50863e6539e947db674090662Dianne Hackborn        if (allowMerge && entries.size() > 0) {
47318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            AppOpEntry last = entries.get(entries.size()-1);
47418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            if (last.getAppEntry() == appEntry) {
47518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                boolean lastExe = last.getTime() != 0;
47618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                boolean entryExe = opEntry.getTime() != 0;
47718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                if (lastExe == entryExe) {
4780dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                    if (DEBUG) Log.d(TAG, "Add op " + opEntry.getOp() + " to package "
4790dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                            + pkgOps.getPackageName() + ": append to " + last);
4808b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn                    last.addOp(opEntry);
48118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    return;
48218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                }
48318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            }
48418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
48527daaab633a80be50863e6539e947db674090662Dianne Hackborn        AppOpEntry entry = appEntry.getOpSwitch(opEntry.getOp());
48627daaab633a80be50863e6539e947db674090662Dianne Hackborn        if (entry != null) {
4878b0afc7fb53b90e522b86ba04bb17c0cba2364abDianne Hackborn            entry.addOp(opEntry);
48827daaab633a80be50863e6539e947db674090662Dianne Hackborn            return;
48927daaab633a80be50863e6539e947db674090662Dianne Hackborn        }
490d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn        entry = new AppOpEntry(pkgOps, opEntry, appEntry, switchOrder);
4910dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        if (DEBUG) Log.d(TAG, "Add op " + opEntry.getOp() + " to package "
4920dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                + pkgOps.getPackageName() + ": making new " + entry);
49318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        entries.add(entry);
49418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    }
49518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
496f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn    public AppOpsManager getAppOpsManager() {
497f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn        return mAppOps;
498f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn    }
499f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn
50018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    public List<AppOpEntry> buildState(OpsTemplate tpl) {
501f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn        return buildState(tpl, 0, null, RECENCY_COMPARATOR);
50218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    }
50318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
5040dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn    private AppEntry getAppEntry(final Context context, final HashMap<String, AppEntry> appEntries,
5050dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            final String packageName, ApplicationInfo appInfo) {
5060dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        AppEntry appEntry = appEntries.get(packageName);
5070dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        if (appEntry == null) {
5080dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            if (appInfo == null) {
5090dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                try {
5100dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                    appInfo = mPm.getApplicationInfo(packageName,
5110dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                            PackageManager.GET_DISABLED_COMPONENTS
5120dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                            | PackageManager.GET_UNINSTALLED_PACKAGES);
5130dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                } catch (PackageManager.NameNotFoundException e) {
5140dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                    Log.w(TAG, "Unable to find info for package " + packageName);
5150dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                    return null;
5160dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                }
5170dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            }
5180dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            appEntry = new AppEntry(this, appInfo);
5190dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            appEntry.loadLabel(context);
5200dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            appEntries.put(packageName, appEntry);
5210dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        }
5220dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        return appEntry;
5230dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn    }
5240dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn
52518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    public List<AppOpEntry> buildState(OpsTemplate tpl, int uid, String packageName) {
526f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn        return buildState(tpl, uid, packageName, RECENCY_COMPARATOR);
527f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn    }
528f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn
529f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn    public List<AppOpEntry> buildState(OpsTemplate tpl, int uid, String packageName,
530f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn            Comparator<AppOpEntry> comparator) {
53118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        final Context context = mContext;
53218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
53318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        final HashMap<String, AppEntry> appEntries = new HashMap<String, AppEntry>();
53427daaab633a80be50863e6539e947db674090662Dianne Hackborn        final List<AppOpEntry> entries = new ArrayList<AppOpEntry>();
5350dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn
53627daaab633a80be50863e6539e947db674090662Dianne Hackborn        final ArrayList<String> perms = new ArrayList<String>();
53727daaab633a80be50863e6539e947db674090662Dianne Hackborn        final ArrayList<Integer> permOps = new ArrayList<Integer>();
538d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn        final int[] opToOrder = new int[AppOpsManager._NUM_OP];
5390dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        for (int i=0; i<tpl.ops.length; i++) {
54027daaab633a80be50863e6539e947db674090662Dianne Hackborn            if (tpl.showPerms[i]) {
54127daaab633a80be50863e6539e947db674090662Dianne Hackborn                String perm = AppOpsManager.opToPermission(tpl.ops[i]);
54227daaab633a80be50863e6539e947db674090662Dianne Hackborn                if (perm != null && !perms.contains(perm)) {
54327daaab633a80be50863e6539e947db674090662Dianne Hackborn                    perms.add(perm);
54427daaab633a80be50863e6539e947db674090662Dianne Hackborn                    permOps.add(tpl.ops[i]);
545d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn                    opToOrder[tpl.ops[i]] = i;
54627daaab633a80be50863e6539e947db674090662Dianne Hackborn                }
5470dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            }
5480dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        }
54918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
55018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        List<AppOpsManager.PackageOps> pkgs;
55118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        if (packageName != null) {
55218b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            pkgs = mAppOps.getOpsForPackage(uid, packageName, tpl.ops);
55318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        } else {
55418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            pkgs = mAppOps.getPackagesForOps(tpl.ops);
55518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
5560dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn
5570dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        if (pkgs != null) {
5580dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            for (int i=0; i<pkgs.size(); i++) {
5590dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                AppOpsManager.PackageOps pkgOps = pkgs.get(i);
5600dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                AppEntry appEntry = getAppEntry(context, appEntries, pkgOps.getPackageName(), null);
5610dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                if (appEntry == null) {
5620dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                    continue;
5630dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                }
5640dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                for (int j=0; j<pkgOps.getOps().size(); j++) {
5650dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                    AppOpsManager.OpEntry opEntry = pkgOps.getOps().get(j);
566d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn                    addOp(entries, pkgOps, appEntry, opEntry, packageName == null,
567d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn                            packageName == null ? 0 : opToOrder[opEntry.getOp()]);
56818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                }
56918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            }
57018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
57118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
5720dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        List<PackageInfo> apps;
5730dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        if (packageName != null) {
5740dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            apps = new ArrayList<PackageInfo>();
5750dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            try {
5760dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                PackageInfo pi = mPm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS);
5770dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                apps.add(pi);
5780dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            } catch (NameNotFoundException e) {
57918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            }
5800dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        } else {
5810dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            String[] permsArray = new String[perms.size()];
5820dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            perms.toArray(permsArray);
5830dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            apps = mPm.getPackagesHoldingPermissions(permsArray, 0);
5840dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        }
5850dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn        for (int i=0; i<apps.size(); i++) {
5860dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            PackageInfo appInfo = apps.get(i);
5870dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            AppEntry appEntry = getAppEntry(context, appEntries, appInfo.packageName,
5880dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                    appInfo.applicationInfo);
5890dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            if (appEntry == null) {
5900dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                continue;
5910dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            }
5920dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            List<AppOpsManager.OpEntry> dummyOps = null;
5930dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn            AppOpsManager.PackageOps pkgOps = null;
5947d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler            if (appInfo.requestedPermissions != null) {
5957d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                for (int j=0; j<appInfo.requestedPermissions.length; j++) {
5967d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                    if (appInfo.requestedPermissionsFlags != null) {
5977d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                        if ((appInfo.requestedPermissionsFlags[j]
5987d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                                & PackageInfo.REQUESTED_PERMISSION_GRANTED) == 0) {
5997d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                            if (DEBUG) Log.d(TAG, "Pkg " + appInfo.packageName + " perm "
6007d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                                    + appInfo.requestedPermissions[j] + " not granted; skipping");
60167e72d9e8a2146ede95c06cac60c2100ad59a33bDanny Baumann                            continue;
6027d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                        }
60318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn                    }
6047d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                    if (DEBUG) Log.d(TAG, "Pkg " + appInfo.packageName + ": requested perm "
6057d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                            + appInfo.requestedPermissions[j]);
6067d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                    for (int k=0; k<perms.size(); k++) {
6077d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                        if (!perms.get(k).equals(appInfo.requestedPermissions[j])) {
6087d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                            continue;
6097d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                        }
6107d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                        if (DEBUG) Log.d(TAG, "Pkg " + appInfo.packageName + " perm " + perms.get(k)
6117d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                                + " has op " + permOps.get(k) + ": " + appEntry.hasOp(permOps.get(k)));
6127d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                        if (appEntry.hasOp(permOps.get(k))) {
6137d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                            continue;
6147d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                        }
6157d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                        if (dummyOps == null) {
6167d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                            dummyOps = new ArrayList<AppOpsManager.OpEntry>();
6177d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                            pkgOps = new AppOpsManager.PackageOps(
6187d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                                    appInfo.packageName, appInfo.applicationInfo.uid, dummyOps);
6197d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler
6207d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                        }
6217d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                        AppOpsManager.OpEntry opEntry = new AppOpsManager.OpEntry(
6225b45c3cb2fdd9299a3fa632047f3da1bec4e868aSvetoslav                                permOps.get(k), AppOpsManager.MODE_ALLOWED, 0, 0, 0, -1, null);
6237d3a4c160cac37b72aa9149952358df4a3912cfbDaniel Sandler                        dummyOps.add(opEntry);
624d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn                        addOp(entries, pkgOps, appEntry, opEntry, packageName == null,
625d69e8dc44173c33c5425158c027bfe44ddcacf85Dianne Hackborn                                packageName == null ? 0 : opToOrder[opEntry.getOp()]);
6260dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                    }
6270dd9902c89e7b705fd73158aadf1bf27843ad201Dianne Hackborn                }
62818b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn            }
62918b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        }
63018b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
63118b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        // Sort the list.
632f467c0acacd834257189dd73f260939a742114f9Dianne Hackborn        Collections.sort(entries, comparator);
63318b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn
63418b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        // Done!
63518b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn        return entries;
63618b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn    }
63718b64f446cd7b9043909b0cd42d1ab364392da24Dianne Hackborn}
638