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