OSDN Git Service

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