Home | History | Annotate | Download | only in applications
      1 /*
      2  * Copyright (C) 2006 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.settings.applications;
     18 
     19 import android.app.Activity;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.content.pm.ApplicationInfo;
     23 import android.content.pm.PackageItemInfo;
     24 import android.content.pm.PackageManager;
     25 import android.content.pm.ResolveInfo;
     26 import android.icu.text.AlphabeticIndex;
     27 import android.os.Bundle;
     28 import android.os.Environment;
     29 import android.os.Handler;
     30 import android.os.LocaleList;
     31 import android.os.UserHandle;
     32 import android.os.UserManager;
     33 import android.preference.PreferenceFrameLayout;
     34 import android.text.TextUtils;
     35 import android.util.ArraySet;
     36 import android.util.Log;
     37 import android.view.LayoutInflater;
     38 import android.view.Menu;
     39 import android.view.MenuInflater;
     40 import android.view.MenuItem;
     41 import android.view.View;
     42 import android.view.ViewGroup;
     43 import android.widget.AbsListView;
     44 import android.widget.AdapterView;
     45 import android.widget.AdapterView.OnItemClickListener;
     46 import android.widget.AdapterView.OnItemSelectedListener;
     47 import android.widget.ArrayAdapter;
     48 import android.widget.BaseAdapter;
     49 import android.widget.Filter;
     50 import android.widget.Filterable;
     51 import android.widget.FrameLayout;
     52 import android.widget.ListView;
     53 import android.widget.SectionIndexer;
     54 import android.widget.Spinner;
     55 import com.android.internal.logging.MetricsProto.MetricsEvent;
     56 import com.android.settings.AppHeader;
     57 import com.android.settings.InstrumentedFragment;
     58 import com.android.settings.R;
     59 import com.android.settings.Settings.AllApplicationsActivity;
     60 import com.android.settings.Settings.HighPowerApplicationsActivity;
     61 import com.android.settings.Settings.NotificationAppListActivity;
     62 import com.android.settings.Settings.OverlaySettingsActivity;
     63 import com.android.settings.Settings.StorageUseActivity;
     64 import com.android.settings.Settings.UsageAccessSettingsActivity;
     65 import com.android.settings.Settings.WriteSettingsActivity;
     66 import com.android.settings.SettingsActivity;
     67 import com.android.settings.Utils;
     68 import com.android.settings.applications.AppStateAppOpsBridge.PermissionState;
     69 import com.android.settings.applications.AppStateUsageBridge.UsageState;
     70 import com.android.settings.dashboard.SummaryLoader;
     71 import com.android.settings.fuelgauge.HighPowerDetail;
     72 import com.android.settings.fuelgauge.PowerWhitelistBackend;
     73 import com.android.settings.notification.AppNotificationSettings;
     74 import com.android.settings.notification.ConfigureNotificationSettings;
     75 import com.android.settings.notification.NotificationBackend;
     76 import com.android.settings.notification.NotificationBackend.AppRow;
     77 import com.android.settingslib.HelpUtils;
     78 import com.android.settingslib.applications.ApplicationsState;
     79 import com.android.settingslib.applications.ApplicationsState.AppEntry;
     80 import com.android.settingslib.applications.ApplicationsState.AppFilter;
     81 import com.android.settingslib.applications.ApplicationsState.CompoundFilter;
     82 import com.android.settingslib.applications.ApplicationsState.VolumeFilter;
     83 
     84 import java.util.ArrayList;
     85 import java.util.Collections;
     86 import java.util.Comparator;
     87 import java.util.List;
     88 import java.util.Locale;
     89 
     90 /**
     91  * Activity to pick an application that will be used to display installation information and
     92  * options to uninstall/delete user data for system applications. This activity
     93  * can be launched through Settings or via the ACTION_MANAGE_PACKAGE_STORAGE
     94  * intent.
     95  */
     96 public class ManageApplications extends InstrumentedFragment
     97         implements OnItemClickListener, OnItemSelectedListener {
     98 
     99     static final String TAG = "ManageApplications";
    100     static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
    101 
    102     // Intent extras.
    103     public static final String EXTRA_CLASSNAME = "classname";
    104     // Used for storage only.
    105     public static final String EXTRA_VOLUME_UUID = "volumeUuid";
    106     public static final String EXTRA_VOLUME_NAME = "volumeName";
    107 
    108     private static final String EXTRA_SORT_ORDER = "sortOrder";
    109     private static final String EXTRA_SHOW_SYSTEM = "showSystem";
    110     private static final String EXTRA_HAS_ENTRIES = "hasEntries";
    111     private static final String EXTRA_HAS_BRIDGE = "hasBridge";
    112 
    113     // attributes used as keys when passing values to InstalledAppDetails activity
    114     public static final String APP_CHG = "chg";
    115 
    116     // constant value that can be used to check return code from sub activity.
    117     private static final int INSTALLED_APP_DETAILS = 1;
    118     private static final int ADVANCED_SETTINGS = 2;
    119 
    120     public static final int SIZE_TOTAL = 0;
    121     public static final int SIZE_INTERNAL = 1;
    122     public static final int SIZE_EXTERNAL = 2;
    123 
    124     // Filter options used for displayed list of applications
    125     // The order which they appear is the order they will show when spinner is present.
    126     public static final int FILTER_APPS_POWER_WHITELIST = 0;
    127     public static final int FILTER_APPS_POWER_WHITELIST_ALL = 1;
    128     public static final int FILTER_APPS_ALL = 2;
    129     public static final int FILTER_APPS_ENABLED = 3;
    130     public static final int FILTER_APPS_DISABLED = 4;
    131     public static final int FILTER_APPS_BLOCKED = 5;
    132     public static final int FILTER_APPS_SILENT = 6;
    133     public static final int FILTER_APPS_SENSITIVE = 7;
    134     public static final int FILTER_APPS_HIDE_NOTIFICATIONS = 8;
    135     public static final int FILTER_APPS_PRIORITY = 9;
    136     public static final int FILTER_APPS_PERSONAL = 10;
    137     public static final int FILTER_APPS_WORK = 11;
    138     public static final int FILTER_APPS_USAGE_ACCESS = 13;
    139     public static final int FILTER_APPS_WITH_OVERLAY = 14;
    140     public static final int FILTER_APPS_WRITE_SETTINGS = 15;
    141 
    142     // This is the string labels for the filter modes above, the order must be kept in sync.
    143     public static final int[] FILTER_LABELS = new int[]{
    144             R.string.high_power_filter_on, // High power whitelist, on
    145             R.string.filter_all_apps,      // Without disabled until used
    146             R.string.filter_all_apps,      // All apps
    147             R.string.filter_enabled_apps,  // Enabled
    148             R.string.filter_apps_disabled, // Disabled
    149             R.string.filter_notif_blocked_apps,   // Blocked Notifications
    150             R.string.filter_notif_silent,    // Silenced Notifications
    151             R.string.filter_notif_sensitive_apps, // Sensitive Notifications
    152             R.string.filter_notif_hide_notifications_apps, // Sensitive Notifications
    153             R.string.filter_notif_priority_apps,  // Priority Notifications
    154             R.string.filter_personal_apps, // Personal
    155             R.string.filter_work_apps,     // Work
    156             R.string.filter_with_domain_urls_apps,     // Domain URLs
    157             R.string.filter_all_apps,      // Usage access screen, never displayed
    158             R.string.filter_overlay_apps,   // Apps with overlay permission
    159             R.string.filter_write_settings_apps,   // Apps that can write system settings
    160     };
    161     // This is the actual mapping to filters from FILTER_ constants above, the order must
    162     // be kept in sync.
    163     public static final AppFilter[] FILTERS = new AppFilter[]{
    164             new CompoundFilter(AppStatePowerBridge.FILTER_POWER_WHITELISTED,
    165                     ApplicationsState.FILTER_ALL_ENABLED),     // High power whitelist, on
    166             new CompoundFilter(ApplicationsState.FILTER_WITHOUT_DISABLED_UNTIL_USED,
    167                     ApplicationsState.FILTER_ALL_ENABLED),     // Without disabled until used
    168             ApplicationsState.FILTER_EVERYTHING,  // All apps
    169             ApplicationsState.FILTER_ALL_ENABLED, // Enabled
    170             ApplicationsState.FILTER_DISABLED,    // Disabled
    171             AppStateNotificationBridge.FILTER_APP_NOTIFICATION_BLOCKED,   // Blocked Notifications
    172             AppStateNotificationBridge.FILTER_APP_NOTIFICATION_SILENCED,   // Silenced Notifications
    173             AppStateNotificationBridge.FILTER_APP_NOTIFICATION_HIDE_SENSITIVE, // Sensitive Notifications
    174             AppStateNotificationBridge.FILTER_APP_NOTIFICATION_HIDE_ALL, // Hide all Notifications
    175             AppStateNotificationBridge.FILTER_APP_NOTIFICATION_PRIORITY,  // Priority Notifications
    176             ApplicationsState.FILTER_PERSONAL,    // Personal
    177             ApplicationsState.FILTER_WORK,        // Work
    178             ApplicationsState.FILTER_WITH_DOMAIN_URLS,   // Apps with Domain URLs
    179             AppStateUsageBridge.FILTER_APP_USAGE, // Apps with Domain URLs
    180             AppStateOverlayBridge.FILTER_SYSTEM_ALERT_WINDOW,   // Apps that can draw overlays
    181             AppStateWriteSettingsBridge.FILTER_WRITE_SETTINGS,  // Apps that can write system settings
    182     };
    183 
    184     // sort order
    185     private int mSortOrder = R.id.sort_order_alpha;
    186 
    187     // whether showing system apps.
    188     private boolean mShowSystem;
    189 
    190     private ApplicationsState mApplicationsState;
    191 
    192     public int mListType;
    193     public int mFilter;
    194 
    195     public ApplicationsAdapter mApplications;
    196 
    197     private View mLoadingContainer;
    198 
    199     private View mListContainer;
    200 
    201     // ListView used to display list
    202     private ListView mListView;
    203 
    204     // Size resource used for packages whose size computation failed for some reason
    205     CharSequence mInvalidSizeStr;
    206 
    207     // layout inflater object used to inflate views
    208     private LayoutInflater mInflater;
    209 
    210     private String mCurrentPkgName;
    211     private int mCurrentUid;
    212     private boolean mFinishAfterDialog;
    213 
    214     private Menu mOptionsMenu;
    215 
    216     public static final int LIST_TYPE_MAIN = 0;
    217     public static final int LIST_TYPE_NOTIFICATION = 1;
    218     public static final int LIST_TYPE_STORAGE = 3;
    219     public static final int LIST_TYPE_USAGE_ACCESS = 4;
    220     public static final int LIST_TYPE_HIGH_POWER = 5;
    221     public static final int LIST_TYPE_OVERLAY = 6;
    222     public static final int LIST_TYPE_WRITE_SETTINGS = 7;
    223 
    224     private View mRootView;
    225 
    226     private View mSpinnerHeader;
    227     private Spinner mFilterSpinner;
    228     private FilterSpinnerAdapter mFilterAdapter;
    229     private NotificationBackend mNotifBackend;
    230     private ResetAppsHelper mResetAppsHelper;
    231     private String mVolumeUuid;
    232     private String mVolumeName;
    233 
    234     @Override
    235     public void onCreate(Bundle savedInstanceState) {
    236         super.onCreate(savedInstanceState);
    237         setHasOptionsMenu(true);
    238         mApplicationsState = ApplicationsState.getInstance(getActivity().getApplication());
    239 
    240         Intent intent = getActivity().getIntent();
    241         Bundle args = getArguments();
    242         String className = args != null ? args.getString(EXTRA_CLASSNAME) : null;
    243         if (className == null) {
    244             className = intent.getComponent().getClassName();
    245         }
    246         if (className.equals(AllApplicationsActivity.class.getName())) {
    247             mShowSystem = true;
    248         } else if (className.equals(NotificationAppListActivity.class.getName())) {
    249             mListType = LIST_TYPE_NOTIFICATION;
    250             mNotifBackend = new NotificationBackend();
    251         } else if (className.equals(StorageUseActivity.class.getName())) {
    252             if (args != null && args.containsKey(EXTRA_VOLUME_UUID)) {
    253                 mVolumeUuid = args.getString(EXTRA_VOLUME_UUID);
    254                 mVolumeName = args.getString(EXTRA_VOLUME_NAME);
    255                 mListType = LIST_TYPE_STORAGE;
    256             } else {
    257                 // No volume selected, display a normal list, sorted by size.
    258                 mListType = LIST_TYPE_MAIN;
    259             }
    260             mSortOrder = R.id.sort_order_size;
    261         } else if (className.equals(UsageAccessSettingsActivity.class.getName())) {
    262             mListType = LIST_TYPE_USAGE_ACCESS;
    263         } else if (className.equals(HighPowerApplicationsActivity.class.getName())) {
    264             mListType = LIST_TYPE_HIGH_POWER;
    265             // Default to showing system.
    266             mShowSystem = true;
    267         } else if (className.equals(OverlaySettingsActivity.class.getName())) {
    268             mListType = LIST_TYPE_OVERLAY;
    269         } else if (className.equals(WriteSettingsActivity.class.getName())) {
    270             mListType = LIST_TYPE_WRITE_SETTINGS;
    271         } else {
    272             mListType = LIST_TYPE_MAIN;
    273         }
    274         mFilter = getDefaultFilter();
    275 
    276         if (savedInstanceState != null) {
    277             mSortOrder = savedInstanceState.getInt(EXTRA_SORT_ORDER, mSortOrder);
    278             mShowSystem = savedInstanceState.getBoolean(EXTRA_SHOW_SYSTEM, mShowSystem);
    279         }
    280 
    281         mInvalidSizeStr = getActivity().getText(R.string.invalid_size_value);
    282 
    283         mResetAppsHelper = new ResetAppsHelper(getActivity());
    284     }
    285 
    286 
    287     @Override
    288     public View onCreateView(LayoutInflater inflater, ViewGroup container,
    289                              Bundle savedInstanceState) {
    290         // initialize the inflater
    291         mInflater = inflater;
    292 
    293         mRootView = inflater.inflate(R.layout.manage_applications_apps, null);
    294         mLoadingContainer = mRootView.findViewById(R.id.loading_container);
    295         mLoadingContainer.setVisibility(View.VISIBLE);
    296         mListContainer = mRootView.findViewById(R.id.list_container);
    297         if (mListContainer != null) {
    298             // Create adapter and list view here
    299             View emptyView = mListContainer.findViewById(com.android.internal.R.id.empty);
    300             ListView lv = (ListView) mListContainer.findViewById(android.R.id.list);
    301             if (emptyView != null) {
    302                 lv.setEmptyView(emptyView);
    303             }
    304             lv.setOnItemClickListener(this);
    305             lv.setSaveEnabled(true);
    306             lv.setItemsCanFocus(true);
    307             lv.setTextFilterEnabled(true);
    308             mListView = lv;
    309             mApplications = new ApplicationsAdapter(mApplicationsState, this, mFilter);
    310             if (savedInstanceState != null) {
    311                 mApplications.mHasReceivedLoadEntries =
    312                         savedInstanceState.getBoolean(EXTRA_HAS_ENTRIES, false);
    313                 mApplications.mHasReceivedBridgeCallback =
    314                         savedInstanceState.getBoolean(EXTRA_HAS_BRIDGE, false);
    315             }
    316             mListView.setAdapter(mApplications);
    317             mListView.setRecyclerListener(mApplications);
    318             mListView.setFastScrollEnabled(isFastScrollEnabled());
    319 
    320             Utils.prepareCustomPreferencesList(container, mRootView, mListView, false);
    321         }
    322 
    323         // We have to do this now because PreferenceFrameLayout looks at it
    324         // only when the view is added.
    325         if (container instanceof PreferenceFrameLayout) {
    326             ((PreferenceFrameLayout.LayoutParams) mRootView.getLayoutParams()).removeBorders = true;
    327         }
    328 
    329         createHeader();
    330 
    331         mResetAppsHelper.onRestoreInstanceState(savedInstanceState);
    332 
    333         return mRootView;
    334     }
    335 
    336     private void createHeader() {
    337         Activity activity = getActivity();
    338         FrameLayout pinnedHeader = (FrameLayout) mRootView.findViewById(R.id.pinned_header);
    339         mSpinnerHeader = (ViewGroup) activity.getLayoutInflater()
    340                 .inflate(R.layout.apps_filter_spinner, pinnedHeader, false);
    341         mFilterSpinner = (Spinner) mSpinnerHeader.findViewById(R.id.filter_spinner);
    342         mFilterAdapter = new FilterSpinnerAdapter(this);
    343         mFilterSpinner.setAdapter(mFilterAdapter);
    344         mFilterSpinner.setOnItemSelectedListener(this);
    345         pinnedHeader.addView(mSpinnerHeader, 0);
    346 
    347         mFilterAdapter.enableFilter(getDefaultFilter());
    348         if (mListType == LIST_TYPE_MAIN) {
    349             if (UserManager.get(getActivity()).getUserProfiles().size() > 1) {
    350                 mFilterAdapter.enableFilter(FILTER_APPS_PERSONAL);
    351                 mFilterAdapter.enableFilter(FILTER_APPS_WORK);
    352             }
    353         }
    354         if (mListType == LIST_TYPE_NOTIFICATION) {
    355             mFilterAdapter.enableFilter(FILTER_APPS_BLOCKED);
    356             mFilterAdapter.enableFilter(FILTER_APPS_SILENT);
    357             mFilterAdapter.enableFilter(FILTER_APPS_SENSITIVE);
    358             mFilterAdapter.enableFilter(FILTER_APPS_HIDE_NOTIFICATIONS);
    359             mFilterAdapter.enableFilter(FILTER_APPS_PRIORITY);
    360         }
    361         if (mListType == LIST_TYPE_HIGH_POWER) {
    362             mFilterAdapter.enableFilter(FILTER_APPS_POWER_WHITELIST_ALL);
    363         }
    364         if (mListType == LIST_TYPE_STORAGE) {
    365             mApplications.setOverrideFilter(new VolumeFilter(mVolumeUuid));
    366         }
    367     }
    368 
    369     @Override
    370     public void onViewCreated(View view, Bundle savedInstanceState) {
    371         super.onViewCreated(view, savedInstanceState);
    372         if (mListType == LIST_TYPE_STORAGE) {
    373             FrameLayout pinnedHeader = (FrameLayout) mRootView.findViewById(R.id.pinned_header);
    374             AppHeader.createAppHeader(getActivity(), null, mVolumeName, null, -1, pinnedHeader);
    375         }
    376     }
    377 
    378     private int getDefaultFilter() {
    379         switch (mListType) {
    380             case LIST_TYPE_USAGE_ACCESS:
    381                 return FILTER_APPS_USAGE_ACCESS;
    382             case LIST_TYPE_HIGH_POWER:
    383                 return FILTER_APPS_POWER_WHITELIST;
    384             case LIST_TYPE_OVERLAY:
    385                 return FILTER_APPS_WITH_OVERLAY;
    386             case LIST_TYPE_WRITE_SETTINGS:
    387                 return FILTER_APPS_WRITE_SETTINGS;
    388             default:
    389                 return FILTER_APPS_ALL;
    390         }
    391     }
    392 
    393     private boolean isFastScrollEnabled() {
    394         switch (mListType) {
    395             case LIST_TYPE_MAIN:
    396             case LIST_TYPE_NOTIFICATION:
    397             case LIST_TYPE_STORAGE:
    398                 return mSortOrder == R.id.sort_order_alpha;
    399             default:
    400                 return false;
    401         }
    402     }
    403 
    404     @Override
    405     protected int getMetricsCategory() {
    406         switch (mListType) {
    407             case LIST_TYPE_MAIN:
    408                 return MetricsEvent.MANAGE_APPLICATIONS;
    409             case LIST_TYPE_NOTIFICATION:
    410                 return MetricsEvent.MANAGE_APPLICATIONS_NOTIFICATIONS;
    411             case LIST_TYPE_STORAGE:
    412                 return MetricsEvent.APPLICATIONS_STORAGE_APPS;
    413             case LIST_TYPE_USAGE_ACCESS:
    414                 return MetricsEvent.USAGE_ACCESS;
    415             case LIST_TYPE_HIGH_POWER:
    416                 return MetricsEvent.APPLICATIONS_HIGH_POWER_APPS;
    417             case LIST_TYPE_OVERLAY:
    418                 return MetricsEvent.SYSTEM_ALERT_WINDOW_APPS;
    419             case LIST_TYPE_WRITE_SETTINGS:
    420                 return MetricsEvent.SYSTEM_ALERT_WINDOW_APPS;
    421             default:
    422                 return MetricsEvent.VIEW_UNKNOWN;
    423         }
    424     }
    425 
    426     @Override
    427     public void onResume() {
    428         super.onResume();
    429         updateView();
    430         updateOptionsMenu();
    431         if (mApplications != null) {
    432             mApplications.resume(mSortOrder);
    433             mApplications.updateLoading();
    434         }
    435     }
    436 
    437     @Override
    438     public void onSaveInstanceState(Bundle outState) {
    439         super.onSaveInstanceState(outState);
    440         mResetAppsHelper.onSaveInstanceState(outState);
    441         outState.putInt(EXTRA_SORT_ORDER, mSortOrder);
    442         outState.putBoolean(EXTRA_SHOW_SYSTEM, mShowSystem);
    443         outState.putBoolean(EXTRA_HAS_ENTRIES, mApplications.mHasReceivedLoadEntries);
    444         outState.putBoolean(EXTRA_HAS_BRIDGE, mApplications.mHasReceivedBridgeCallback);
    445     }
    446 
    447     @Override
    448     public void onPause() {
    449         super.onPause();
    450         if (mApplications != null) {
    451             mApplications.pause();
    452         }
    453     }
    454 
    455     @Override
    456     public void onStop() {
    457         super.onStop();
    458         mResetAppsHelper.stop();
    459     }
    460 
    461     @Override
    462     public void onDestroyView() {
    463         super.onDestroyView();
    464 
    465         if (mApplications != null) {
    466             mApplications.release();
    467         }
    468         mRootView = null;
    469     }
    470 
    471     @Override
    472     public void onActivityResult(int requestCode, int resultCode, Intent data) {
    473         if (requestCode == INSTALLED_APP_DETAILS && mCurrentPkgName != null) {
    474             if (mListType == LIST_TYPE_NOTIFICATION) {
    475                 mApplications.mExtraInfoBridge.forceUpdate(mCurrentPkgName, mCurrentUid);
    476             } else if (mListType == LIST_TYPE_HIGH_POWER || mListType == LIST_TYPE_OVERLAY
    477                     || mListType == LIST_TYPE_WRITE_SETTINGS) {
    478                 if (mFinishAfterDialog) {
    479                     getActivity().onBackPressed();
    480                 } else {
    481                     mApplications.mExtraInfoBridge.forceUpdate(mCurrentPkgName, mCurrentUid);
    482                 }
    483             } else {
    484                 mApplicationsState.requestSize(mCurrentPkgName, UserHandle.getUserId(mCurrentUid));
    485             }
    486         }
    487     }
    488 
    489     // utility method used to start sub activity
    490     private void startApplicationDetailsActivity() {
    491         switch (mListType) {
    492             case LIST_TYPE_NOTIFICATION:
    493                 startAppInfoFragment(AppNotificationSettings.class,
    494                         R.string.app_notifications_title);
    495                 break;
    496             case LIST_TYPE_USAGE_ACCESS:
    497                 startAppInfoFragment(UsageAccessDetails.class, R.string.usage_access);
    498                 break;
    499             case LIST_TYPE_STORAGE:
    500                 startAppInfoFragment(AppStorageSettings.class, R.string.storage_settings);
    501                 break;
    502             case LIST_TYPE_HIGH_POWER:
    503                 HighPowerDetail.show(this, mCurrentPkgName, INSTALLED_APP_DETAILS,
    504                         mFinishAfterDialog);
    505                 break;
    506             case LIST_TYPE_OVERLAY:
    507                 startAppInfoFragment(DrawOverlayDetails.class, R.string.overlay_settings);
    508                 break;
    509             case LIST_TYPE_WRITE_SETTINGS:
    510                 startAppInfoFragment(WriteSettingsDetails.class, R.string.write_system_settings);
    511                 break;
    512             // TODO: Figure out if there is a way where we can spin up the profile's settings
    513             // process ahead of time, to avoid a long load of data when user clicks on a managed app.
    514             // Maybe when they load the list of apps that contains managed profile apps.
    515             default:
    516                 startAppInfoFragment(InstalledAppDetails.class, R.string.application_info_label);
    517                 break;
    518         }
    519     }
    520 
    521     private void startAppInfoFragment(Class<?> fragment, int titleRes) {
    522         AppInfoBase.startAppInfoFragment(fragment, titleRes, mCurrentPkgName, mCurrentUid, this,
    523                 INSTALLED_APP_DETAILS);
    524     }
    525 
    526     @Override
    527     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    528         HelpUtils.prepareHelpMenuItem(getActivity(), menu, mListType == LIST_TYPE_MAIN
    529                 ? R.string.help_uri_apps : R.string.help_uri_notifications, getClass().getName());
    530         mOptionsMenu = menu;
    531         inflater.inflate(R.menu.manage_apps, menu);
    532         updateOptionsMenu();
    533     }
    534 
    535     @Override
    536     public void onPrepareOptionsMenu(Menu menu) {
    537         updateOptionsMenu();
    538     }
    539 
    540     @Override
    541     public void onDestroyOptionsMenu() {
    542         mOptionsMenu = null;
    543     }
    544 
    545     void updateOptionsMenu() {
    546         if (mOptionsMenu == null) {
    547             return;
    548         }
    549         mOptionsMenu.findItem(R.id.advanced).setVisible(
    550                 mListType == LIST_TYPE_MAIN || mListType == LIST_TYPE_NOTIFICATION);
    551 
    552         mOptionsMenu.findItem(R.id.sort_order_alpha).setVisible(mListType == LIST_TYPE_STORAGE
    553                 && mSortOrder != R.id.sort_order_alpha);
    554         mOptionsMenu.findItem(R.id.sort_order_size).setVisible(mListType == LIST_TYPE_STORAGE
    555                 && mSortOrder != R.id.sort_order_size);
    556 
    557         mOptionsMenu.findItem(R.id.show_system).setVisible(!mShowSystem
    558                 && mListType != LIST_TYPE_HIGH_POWER);
    559         mOptionsMenu.findItem(R.id.hide_system).setVisible(mShowSystem
    560                 && mListType != LIST_TYPE_HIGH_POWER);
    561     }
    562 
    563     @Override
    564     public boolean onOptionsItemSelected(MenuItem item) {
    565         int menuId = item.getItemId();
    566         switch (item.getItemId()) {
    567             case R.id.sort_order_alpha:
    568             case R.id.sort_order_size:
    569                 mSortOrder = menuId;
    570                 mListView.setFastScrollEnabled(isFastScrollEnabled());
    571                 if (mApplications != null) {
    572                     mApplications.rebuild(mSortOrder);
    573                 }
    574                 break;
    575             case R.id.show_system:
    576             case R.id.hide_system:
    577                 mShowSystem = !mShowSystem;
    578                 mApplications.rebuild(false);
    579                 break;
    580             case R.id.reset_app_preferences:
    581                 mResetAppsHelper.buildResetDialog();
    582                 return true;
    583             case R.id.advanced:
    584                 if (mListType == LIST_TYPE_NOTIFICATION) {
    585                     ((SettingsActivity) getActivity()).startPreferencePanel(
    586                             ConfigureNotificationSettings.class.getName(), null,
    587                             R.string.configure_notification_settings, null, this, ADVANCED_SETTINGS);
    588                 } else {
    589                     ((SettingsActivity) getActivity()).startPreferencePanel(
    590                             AdvancedAppSettings.class.getName(), null, R.string.configure_apps,
    591                             null, this, ADVANCED_SETTINGS);
    592                 }
    593                 return true;
    594             default:
    595                 // Handle the home button
    596                 return false;
    597         }
    598         updateOptionsMenu();
    599         return true;
    600     }
    601 
    602     @Override
    603     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    604         if (mApplications != null && mApplications.getCount() > position) {
    605             ApplicationsState.AppEntry entry = mApplications.getAppEntry(position);
    606             mCurrentPkgName = entry.info.packageName;
    607             mCurrentUid = entry.info.uid;
    608             startApplicationDetailsActivity();
    609         }
    610     }
    611 
    612     @Override
    613     public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
    614         mFilter = mFilterAdapter.getFilter(position);
    615         mApplications.setFilter(mFilter);
    616         if (DEBUG) Log.d(TAG, "Selecting filter " + mFilter);
    617     }
    618 
    619     @Override
    620     public void onNothingSelected(AdapterView<?> parent) {
    621     }
    622 
    623     public void updateView() {
    624         updateOptionsMenu();
    625         final Activity host = getActivity();
    626         if (host != null) {
    627             host.invalidateOptionsMenu();
    628         }
    629     }
    630 
    631     public void setHasDisabled(boolean hasDisabledApps) {
    632         if (mListType != LIST_TYPE_MAIN) {
    633             return;
    634         }
    635         mFilterAdapter.setFilterEnabled(FILTER_APPS_ENABLED, hasDisabledApps);
    636         mFilterAdapter.setFilterEnabled(FILTER_APPS_DISABLED, hasDisabledApps);
    637     }
    638 
    639     static class FilterSpinnerAdapter extends ArrayAdapter<CharSequence> {
    640 
    641         private final ManageApplications mManageApplications;
    642 
    643         // Use ArrayAdapter for view logic, but have our own list for managing
    644         // the options available.
    645         private final ArrayList<Integer> mFilterOptions = new ArrayList<>();
    646 
    647         public FilterSpinnerAdapter(ManageApplications manageApplications) {
    648             super(manageApplications.getActivity(), R.layout.filter_spinner_item);
    649             setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    650             mManageApplications = manageApplications;
    651         }
    652 
    653         public int getFilter(int position) {
    654             return mFilterOptions.get(position);
    655         }
    656 
    657         public void setFilterEnabled(int filter, boolean enabled) {
    658             if (enabled) {
    659                 enableFilter(filter);
    660             } else {
    661                 disableFilter(filter);
    662             }
    663         }
    664 
    665         public void enableFilter(int filter) {
    666             if (mFilterOptions.contains(filter)) return;
    667             if (DEBUG) Log.d(TAG, "Enabling filter " + filter);
    668             mFilterOptions.add(filter);
    669             Collections.sort(mFilterOptions);
    670             mManageApplications.mSpinnerHeader.setVisibility(
    671                     mFilterOptions.size() > 1 ? View.VISIBLE : View.GONE);
    672             notifyDataSetChanged();
    673             if (mFilterOptions.size() == 1) {
    674                 if (DEBUG) Log.d(TAG, "Auto selecting filter " + filter);
    675                 mManageApplications.mFilterSpinner.setSelection(0);
    676                 mManageApplications.onItemSelected(null, null, 0, 0);
    677             }
    678         }
    679 
    680         public void disableFilter(int filter) {
    681             if (!mFilterOptions.remove((Integer) filter)) {
    682                 return;
    683             }
    684             if (DEBUG) Log.d(TAG, "Disabling filter " + filter);
    685             Collections.sort(mFilterOptions);
    686             mManageApplications.mSpinnerHeader.setVisibility(
    687                     mFilterOptions.size() > 1 ? View.VISIBLE : View.GONE);
    688             notifyDataSetChanged();
    689             if (mManageApplications.mFilter == filter) {
    690                 if (mFilterOptions.size() > 0) {
    691                     if (DEBUG) Log.d(TAG, "Auto selecting filter " + mFilterOptions.get(0));
    692                     mManageApplications.mFilterSpinner.setSelection(0);
    693                     mManageApplications.onItemSelected(null, null, 0, 0);
    694                 }
    695             }
    696         }
    697 
    698         @Override
    699         public int getCount() {
    700             return mFilterOptions.size();
    701         }
    702 
    703         @Override
    704         public CharSequence getItem(int position) {
    705             return getFilterString(mFilterOptions.get(position));
    706         }
    707 
    708         private CharSequence getFilterString(int filter) {
    709             return mManageApplications.getString(FILTER_LABELS[filter]);
    710         }
    711 
    712     }
    713 
    714     /*
    715      * Custom adapter implementation for the ListView
    716      * This adapter maintains a map for each displayed application and its properties
    717      * An index value on each AppInfo object indicates the correct position or index
    718      * in the list. If the list gets updated dynamically when the user is viewing the list of
    719      * applications, we need to return the correct index of position. This is done by mapping
    720      * the getId methods via the package name into the internal maps and indices.
    721      * The order of applications in the list is mirrored in mAppLocalList
    722      */
    723     static class ApplicationsAdapter extends BaseAdapter implements Filterable,
    724             ApplicationsState.Callbacks, AppStateBaseBridge.Callback,
    725             AbsListView.RecyclerListener, SectionIndexer {
    726         private static final SectionInfo[] EMPTY_SECTIONS = new SectionInfo[0];
    727 
    728         private final ApplicationsState mState;
    729         private final ApplicationsState.Session mSession;
    730         private final ManageApplications mManageApplications;
    731         private final Context mContext;
    732         private final ArrayList<View> mActive = new ArrayList<View>();
    733         private final AppStateBaseBridge mExtraInfoBridge;
    734         private final Handler mBgHandler;
    735         private final Handler mFgHandler;
    736         private int mFilterMode;
    737         private ArrayList<ApplicationsState.AppEntry> mBaseEntries;
    738         private ArrayList<ApplicationsState.AppEntry> mEntries;
    739         private boolean mResumed;
    740         private int mLastSortMode = -1;
    741         private int mWhichSize = SIZE_TOTAL;
    742         CharSequence mCurFilterPrefix;
    743         private PackageManager mPm;
    744         private AppFilter mOverrideFilter;
    745         private boolean mHasReceivedLoadEntries;
    746         private boolean mHasReceivedBridgeCallback;
    747 
    748         private AlphabeticIndex.ImmutableIndex<Locale> mIndex;
    749         private SectionInfo[] mSections = EMPTY_SECTIONS;
    750         private int[] mPositionToSectionIndex;
    751 
    752         private Filter mFilter = new Filter() {
    753             @Override
    754             protected FilterResults performFiltering(CharSequence constraint) {
    755                 ArrayList<ApplicationsState.AppEntry> entries
    756                         = applyPrefixFilter(constraint, mBaseEntries);
    757                 FilterResults fr = new FilterResults();
    758                 fr.values = entries;
    759                 fr.count = entries.size();
    760                 return fr;
    761             }
    762 
    763             @Override
    764             @SuppressWarnings("unchecked")
    765             protected void publishResults(CharSequence constraint, FilterResults results) {
    766                 mCurFilterPrefix = constraint;
    767                 mEntries = (ArrayList<ApplicationsState.AppEntry>) results.values;
    768                 rebuildSections();
    769                 notifyDataSetChanged();
    770             }
    771         };
    772 
    773         public ApplicationsAdapter(ApplicationsState state, ManageApplications manageApplications,
    774                                    int filterMode) {
    775             mState = state;
    776             mFgHandler = new Handler();
    777             mBgHandler = new Handler(mState.getBackgroundLooper());
    778             mSession = state.newSession(this);
    779             mManageApplications = manageApplications;
    780             mContext = manageApplications.getActivity();
    781             mPm = mContext.getPackageManager();
    782             mFilterMode = filterMode;
    783             if (mManageApplications.mListType == LIST_TYPE_NOTIFICATION) {
    784                 mExtraInfoBridge = new AppStateNotificationBridge(mContext, mState, this,
    785                         manageApplications.mNotifBackend);
    786             } else if (mManageApplications.mListType == LIST_TYPE_USAGE_ACCESS) {
    787                 mExtraInfoBridge = new AppStateUsageBridge(mContext, mState, this);
    788             } else if (mManageApplications.mListType == LIST_TYPE_HIGH_POWER) {
    789                 mExtraInfoBridge = new AppStatePowerBridge(mState, this);
    790             } else if (mManageApplications.mListType == LIST_TYPE_OVERLAY) {
    791                 mExtraInfoBridge = new AppStateOverlayBridge(mContext, mState, this);
    792             } else if (mManageApplications.mListType == LIST_TYPE_WRITE_SETTINGS) {
    793                 mExtraInfoBridge = new AppStateWriteSettingsBridge(mContext, mState, this);
    794             } else {
    795                 mExtraInfoBridge = null;
    796             }
    797         }
    798 
    799         public void setOverrideFilter(AppFilter overrideFilter) {
    800             mOverrideFilter = overrideFilter;
    801             rebuild(true);
    802         }
    803 
    804         public void setFilter(int filter) {
    805             mFilterMode = filter;
    806             rebuild(true);
    807         }
    808 
    809         public void resume(int sort) {
    810             if (DEBUG) Log.i(TAG, "Resume!  mResumed=" + mResumed);
    811             if (!mResumed) {
    812                 mResumed = true;
    813                 mSession.resume();
    814                 mLastSortMode = sort;
    815                 if (mExtraInfoBridge != null) {
    816                     mExtraInfoBridge.resume();
    817                 }
    818                 rebuild(false);
    819             } else {
    820                 rebuild(sort);
    821             }
    822         }
    823 
    824         public void pause() {
    825             if (mResumed) {
    826                 mResumed = false;
    827                 mSession.pause();
    828                 if (mExtraInfoBridge != null) {
    829                     mExtraInfoBridge.pause();
    830                 }
    831             }
    832         }
    833 
    834         public void release() {
    835             mSession.release();
    836             if (mExtraInfoBridge != null) {
    837                 mExtraInfoBridge.release();
    838             }
    839         }
    840 
    841         public void rebuild(int sort) {
    842             if (sort == mLastSortMode) {
    843                 return;
    844             }
    845             mLastSortMode = sort;
    846             rebuild(true);
    847         }
    848 
    849         public void rebuild(boolean eraseold) {
    850             if (!mHasReceivedLoadEntries
    851                     || (mExtraInfoBridge != null && !mHasReceivedBridgeCallback)) {
    852                 // Don't rebuild the list until all the app entries are loaded.
    853                 return;
    854             }
    855             if (DEBUG) Log.i(TAG, "Rebuilding app list...");
    856             ApplicationsState.AppFilter filterObj;
    857             Comparator<AppEntry> comparatorObj;
    858             boolean emulated = Environment.isExternalStorageEmulated();
    859             if (emulated) {
    860                 mWhichSize = SIZE_TOTAL;
    861             } else {
    862                 mWhichSize = SIZE_INTERNAL;
    863             }
    864             filterObj = FILTERS[mFilterMode];
    865             if (mOverrideFilter != null) {
    866                 filterObj = mOverrideFilter;
    867             }
    868             if (!mManageApplications.mShowSystem) {
    869                 filterObj = new CompoundFilter(filterObj,
    870                         ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER);
    871             }
    872             switch (mLastSortMode) {
    873                 case R.id.sort_order_size:
    874                     switch (mWhichSize) {
    875                         case SIZE_INTERNAL:
    876                             comparatorObj = ApplicationsState.INTERNAL_SIZE_COMPARATOR;
    877                             break;
    878                         case SIZE_EXTERNAL:
    879                             comparatorObj = ApplicationsState.EXTERNAL_SIZE_COMPARATOR;
    880                             break;
    881                         default:
    882                             comparatorObj = ApplicationsState.SIZE_COMPARATOR;
    883                             break;
    884                     }
    885                     break;
    886                 default:
    887                     comparatorObj = ApplicationsState.ALPHA_COMPARATOR;
    888                     break;
    889             }
    890             filterObj = new CompoundFilter(filterObj, ApplicationsState.FILTER_NOT_HIDE);
    891 
    892             AppFilter finalFilterObj = filterObj;
    893             mBgHandler.post(() -> {
    894                 final ArrayList<AppEntry> entries = mSession.rebuild(finalFilterObj,
    895                         comparatorObj, false);
    896                 if (entries != null) {
    897                     mFgHandler.post(() -> onRebuildComplete(entries));
    898                 }
    899             });
    900         }
    901 
    902 
    903         static private boolean packageNameEquals(PackageItemInfo info1, PackageItemInfo info2) {
    904             if (info1 == null || info2 == null) {
    905                 return false;
    906             }
    907             if (info1.packageName == null || info2.packageName == null) {
    908                 return false;
    909             }
    910             return info1.packageName.equals(info2.packageName);
    911         }
    912 
    913         private ArrayList<ApplicationsState.AppEntry> removeDuplicateIgnoringUser(
    914                 ArrayList<ApplicationsState.AppEntry> entries)
    915         {
    916             int size = entries.size();
    917             // returnList will not have more entries than entries
    918             ArrayList<ApplicationsState.AppEntry> returnEntries = new
    919                     ArrayList<ApplicationsState.AppEntry>(size);
    920 
    921             // assume appinfo of same package but different users are grouped together
    922             PackageItemInfo lastInfo = null;
    923             for (int i = 0; i < size; i++) {
    924                 AppEntry appEntry = entries.get(i);
    925                 PackageItemInfo info = appEntry.info;
    926                 if (!packageNameEquals(lastInfo, appEntry.info)) {
    927                     returnEntries.add(appEntry);
    928                 }
    929                 lastInfo = info;
    930             }
    931             returnEntries.trimToSize();
    932             return returnEntries;
    933         }
    934 
    935         @Override
    936         public void onRebuildComplete(ArrayList<AppEntry> entries) {
    937             if (mFilterMode == FILTER_APPS_POWER_WHITELIST ||
    938                     mFilterMode == FILTER_APPS_POWER_WHITELIST_ALL) {
    939                 entries = removeDuplicateIgnoringUser(entries);
    940             }
    941             mBaseEntries = entries;
    942             if (mBaseEntries != null) {
    943                 mEntries = applyPrefixFilter(mCurFilterPrefix, mBaseEntries);
    944                 rebuildSections();
    945             } else {
    946                 mEntries = null;
    947                 mSections = EMPTY_SECTIONS;
    948                 mPositionToSectionIndex = null;
    949             }
    950 
    951             notifyDataSetChanged();
    952 
    953             if (mSession.getAllApps().size() != 0
    954                     && mManageApplications.mListContainer.getVisibility() != View.VISIBLE) {
    955                 Utils.handleLoadingContainer(mManageApplications.mLoadingContainer,
    956                         mManageApplications.mListContainer, true, true);
    957             }
    958             if (mManageApplications.mListType == LIST_TYPE_USAGE_ACCESS) {
    959                 // No enabled or disabled filters for usage access.
    960                 return;
    961             }
    962 
    963             mManageApplications.setHasDisabled(mState.haveDisabledApps());
    964         }
    965 
    966         private void rebuildSections() {
    967             if (mEntries!= null && mManageApplications.mListView.isFastScrollEnabled()) {
    968                 // Rebuild sections
    969                 if (mIndex == null) {
    970                     LocaleList locales = mContext.getResources().getConfiguration().getLocales();
    971                     if (locales.size() == 0) {
    972                         locales = new LocaleList(Locale.ENGLISH);
    973                     }
    974                     AlphabeticIndex<Locale> index = new AlphabeticIndex<>(locales.get(0));
    975                     int localeCount = locales.size();
    976                     for (int i = 1; i < localeCount; i++) {
    977                         index.addLabels(locales.get(i));
    978                     }
    979                     // Ensure we always have some base English locale buckets
    980                     index.addLabels(Locale.ENGLISH);
    981                     mIndex = index.buildImmutableIndex();
    982                 }
    983 
    984                 ArrayList<SectionInfo> sections = new ArrayList<>();
    985                 int lastSecId = -1;
    986                 int totalEntries = mEntries.size();
    987                 mPositionToSectionIndex = new int[totalEntries];
    988 
    989                 for (int pos = 0; pos < totalEntries; pos++) {
    990                     String label = mEntries.get(pos).label;
    991                     int secId = mIndex.getBucketIndex(TextUtils.isEmpty(label) ? "" : label);
    992                     if (secId != lastSecId) {
    993                         lastSecId = secId;
    994                         sections.add(new SectionInfo(mIndex.getBucket(secId).getLabel(), pos));
    995                     }
    996                     mPositionToSectionIndex[pos] = sections.size() - 1;
    997                 }
    998                 mSections = sections.toArray(EMPTY_SECTIONS);
    999             } else {
   1000                 mSections = EMPTY_SECTIONS;
   1001                 mPositionToSectionIndex = null;
   1002             }
   1003         }
   1004 
   1005         private void updateLoading() {
   1006             Utils.handleLoadingContainer(mManageApplications.mLoadingContainer,
   1007                     mManageApplications.mListContainer,
   1008                     mHasReceivedLoadEntries && mSession.getAllApps().size() != 0, false);
   1009         }
   1010 
   1011         ArrayList<ApplicationsState.AppEntry> applyPrefixFilter(CharSequence prefix,
   1012                                                                 ArrayList<ApplicationsState.AppEntry> origEntries) {
   1013             if (prefix == null || prefix.length() == 0) {
   1014                 return origEntries;
   1015             } else {
   1016                 String prefixStr = ApplicationsState.normalize(prefix.toString());
   1017                 final String spacePrefixStr = " " + prefixStr;
   1018                 ArrayList<ApplicationsState.AppEntry> newEntries
   1019                         = new ArrayList<ApplicationsState.AppEntry>();
   1020                 for (int i = 0; i < origEntries.size(); i++) {
   1021                     ApplicationsState.AppEntry entry = origEntries.get(i);
   1022                     String nlabel = entry.getNormalizedLabel();
   1023                     if (nlabel.startsWith(prefixStr) || nlabel.indexOf(spacePrefixStr) != -1) {
   1024                         newEntries.add(entry);
   1025                     }
   1026                 }
   1027                 return newEntries;
   1028             }
   1029         }
   1030 
   1031         @Override
   1032         public void onExtraInfoUpdated() {
   1033             mHasReceivedBridgeCallback = true;
   1034             rebuild(false);
   1035         }
   1036 
   1037         @Override
   1038         public void onRunningStateChanged(boolean running) {
   1039             mManageApplications.getActivity().setProgressBarIndeterminateVisibility(running);
   1040         }
   1041 
   1042         @Override
   1043         public void onPackageListChanged() {
   1044             rebuild(false);
   1045         }
   1046 
   1047         @Override
   1048         public void onPackageIconChanged() {
   1049             // We ensure icons are loaded when their item is displayed, so
   1050             // don't care about icons loaded in the background.
   1051         }
   1052 
   1053         @Override
   1054         public void onLoadEntriesCompleted() {
   1055             mHasReceivedLoadEntries = true;
   1056             // We may have been skipping rebuilds until this came in, trigger one now.
   1057             rebuild(false);
   1058         }
   1059 
   1060         @Override
   1061         public void onPackageSizeChanged(String packageName) {
   1062             for (int i = 0; i < mActive.size(); i++) {
   1063                 AppViewHolder holder = (AppViewHolder) mActive.get(i).getTag();
   1064                 if (holder.entry.info.packageName.equals(packageName)) {
   1065                     synchronized (holder.entry) {
   1066                         updateSummary(holder);
   1067                     }
   1068                     if (holder.entry.info.packageName.equals(mManageApplications.mCurrentPkgName)
   1069                             && mLastSortMode == R.id.sort_order_size) {
   1070                         // We got the size information for the last app the
   1071                         // user viewed, and are sorting by size...  they may
   1072                         // have cleared data, so we immediately want to resort
   1073                         // the list with the new size to reflect it to the user.
   1074                         rebuild(false);
   1075                     }
   1076                     return;
   1077                 }
   1078             }
   1079         }
   1080 
   1081         @Override
   1082         public void onLauncherInfoChanged() {
   1083             if (!mManageApplications.mShowSystem) {
   1084                 rebuild(false);
   1085             }
   1086         }
   1087 
   1088         @Override
   1089         public void onAllSizesComputed() {
   1090             if (mLastSortMode == R.id.sort_order_size) {
   1091                 rebuild(false);
   1092             }
   1093         }
   1094 
   1095         public int getCount() {
   1096             return mEntries != null ? mEntries.size() : 0;
   1097         }
   1098 
   1099         public Object getItem(int position) {
   1100             return mEntries.get(position);
   1101         }
   1102 
   1103         public ApplicationsState.AppEntry getAppEntry(int position) {
   1104             return mEntries.get(position);
   1105         }
   1106 
   1107         public long getItemId(int position) {
   1108             return mEntries.get(position).id;
   1109         }
   1110 
   1111         @Override
   1112         public boolean areAllItemsEnabled() {
   1113             return false;
   1114         }
   1115 
   1116         @Override
   1117         public boolean isEnabled(int position) {
   1118             if (mManageApplications.mListType != LIST_TYPE_HIGH_POWER) {
   1119                 return true;
   1120             }
   1121             ApplicationsState.AppEntry entry = mEntries.get(position);
   1122             return !PowerWhitelistBackend.getInstance().isSysWhitelisted(entry.info.packageName);
   1123         }
   1124 
   1125         public View getView(int position, View convertView, ViewGroup parent) {
   1126             // A ViewHolder keeps references to children views to avoid unnecessary calls
   1127             // to findViewById() on each row.
   1128             AppViewHolder holder = AppViewHolder.createOrRecycle(mManageApplications.mInflater,
   1129                     convertView);
   1130             convertView = holder.rootView;
   1131 
   1132             // Bind the data efficiently with the holder
   1133             ApplicationsState.AppEntry entry = mEntries.get(position);
   1134             synchronized (entry) {
   1135                 holder.entry = entry;
   1136                 if (entry.label != null) {
   1137                     holder.appName.setText(entry.label);
   1138                 }
   1139                 mState.ensureIcon(entry);
   1140                 if (entry.icon != null) {
   1141                     holder.appIcon.setImageDrawable(entry.icon);
   1142                 }
   1143                 updateSummary(holder);
   1144                 if ((entry.info.flags & ApplicationInfo.FLAG_INSTALLED) == 0) {
   1145                     holder.disabled.setVisibility(View.VISIBLE);
   1146                     holder.disabled.setText(R.string.not_installed);
   1147                 } else if (!entry.info.enabled) {
   1148                     holder.disabled.setVisibility(View.VISIBLE);
   1149                     holder.disabled.setText(R.string.disabled);
   1150                 } else {
   1151                     holder.disabled.setVisibility(View.GONE);
   1152                 }
   1153             }
   1154             mActive.remove(convertView);
   1155             mActive.add(convertView);
   1156             convertView.setEnabled(isEnabled(position));
   1157             return convertView;
   1158         }
   1159 
   1160         private void updateSummary(AppViewHolder holder) {
   1161             switch (mManageApplications.mListType) {
   1162                 case LIST_TYPE_NOTIFICATION:
   1163                     if (holder.entry.extraInfo != null) {
   1164                         holder.summary.setText(InstalledAppDetails.getNotificationSummary(
   1165                                 (AppRow) holder.entry.extraInfo, mContext));
   1166                     } else {
   1167                         holder.summary.setText(null);
   1168                     }
   1169                     break;
   1170 
   1171                 case LIST_TYPE_USAGE_ACCESS:
   1172                     if (holder.entry.extraInfo != null) {
   1173                         holder.summary.setText((new UsageState((PermissionState) holder.entry
   1174                                 .extraInfo)).isPermissible() ? R.string.switch_on_text :
   1175                                 R.string.switch_off_text);
   1176                     } else {
   1177                         holder.summary.setText(null);
   1178                     }
   1179                     break;
   1180 
   1181                 case LIST_TYPE_HIGH_POWER:
   1182                     holder.summary.setText(HighPowerDetail.getSummary(mContext, holder.entry));
   1183                     break;
   1184 
   1185                 case LIST_TYPE_OVERLAY:
   1186                     holder.summary.setText(DrawOverlayDetails.getSummary(mContext, holder.entry));
   1187                     break;
   1188 
   1189                 case LIST_TYPE_WRITE_SETTINGS:
   1190                     holder.summary.setText(WriteSettingsDetails.getSummary(mContext,
   1191                             holder.entry));
   1192                     break;
   1193 
   1194                 default:
   1195                     holder.updateSizeText(mManageApplications.mInvalidSizeStr, mWhichSize);
   1196                     break;
   1197             }
   1198         }
   1199 
   1200         @Override
   1201         public Filter getFilter() {
   1202             return mFilter;
   1203         }
   1204 
   1205         @Override
   1206         public void onMovedToScrapHeap(View view) {
   1207             mActive.remove(view);
   1208         }
   1209 
   1210         @Override
   1211         public Object[] getSections() {
   1212             return mSections;
   1213         }
   1214 
   1215         @Override
   1216         public int getPositionForSection(int sectionIndex) {
   1217             return mSections[sectionIndex].position;
   1218         }
   1219 
   1220         @Override
   1221         public int getSectionForPosition(int position) {
   1222             return mPositionToSectionIndex[position];
   1223         }
   1224     }
   1225 
   1226     private static class SummaryProvider implements SummaryLoader.SummaryProvider {
   1227 
   1228         private final Context mContext;
   1229         private final SummaryLoader mLoader;
   1230         private ApplicationsState.Session mSession;
   1231 
   1232         private SummaryProvider(Context context, SummaryLoader loader) {
   1233             mContext = context;
   1234             mLoader = loader;
   1235         }
   1236 
   1237         @Override
   1238         public void setListening(boolean listening) {
   1239             if (listening) {
   1240                 new AppCounter(mContext) {
   1241                     @Override
   1242                     protected void onCountComplete(int num) {
   1243                         mLoader.setSummary(SummaryProvider.this,
   1244                                 mContext.getString(R.string.apps_summary, num));
   1245                     }
   1246 
   1247                     @Override
   1248                     protected boolean includeInCount(ApplicationInfo info) {
   1249                         if ((info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
   1250                             return true;
   1251                         } else if ((info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
   1252                             return true;
   1253                         }
   1254                         Intent launchIntent = new Intent(Intent.ACTION_MAIN, null)
   1255                                 .addCategory(Intent.CATEGORY_LAUNCHER)
   1256                                 .setPackage(info.packageName);
   1257                         int userId = UserHandle.getUserId(info.uid);
   1258                         List<ResolveInfo> intents = mPm.queryIntentActivitiesAsUser(
   1259                                 launchIntent,
   1260                                 PackageManager.GET_DISABLED_COMPONENTS
   1261                                         | PackageManager.MATCH_DIRECT_BOOT_AWARE
   1262                                         | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
   1263                                 userId);
   1264                         return intents != null && intents.size() != 0;
   1265                     }
   1266                 }.execute();
   1267             }
   1268         }
   1269     }
   1270 
   1271     private static class SectionInfo {
   1272         final String label;
   1273         final int position;
   1274 
   1275         public SectionInfo(String label, int position) {
   1276             this.label = label;
   1277             this.position = position;
   1278         }
   1279 
   1280         @Override
   1281         public String toString() {
   1282             return label;
   1283         }
   1284     }
   1285 
   1286     public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY
   1287             = new SummaryLoader.SummaryProviderFactory() {
   1288         @Override
   1289         public SummaryLoader.SummaryProvider createSummaryProvider(Activity activity,
   1290                                                                    SummaryLoader summaryLoader) {
   1291             return new SummaryProvider(activity, summaryLoader);
   1292         }
   1293     };
   1294 }
   1295