OSDN Git Service

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