Home | History | Annotate | Download | only in applications
      1 /**
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
      5  * use this file except in compliance with the License. You may obtain a copy
      6  * 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, WITHOUT
     12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     13  * License for the specific language governing permissions and limitations
     14  * under the License.
     15  */
     16 
     17 package com.android.settings.applications;
     18 
     19 import android.Manifest.permission;
     20 import android.app.Activity;
     21 import android.app.ActivityManager;
     22 import android.app.AlertDialog;
     23 import android.app.LoaderManager.LoaderCallbacks;
     24 import android.app.Notification;
     25 import android.app.admin.DevicePolicyManager;
     26 import android.content.ActivityNotFoundException;
     27 import android.content.BroadcastReceiver;
     28 import android.content.ComponentName;
     29 import android.content.Context;
     30 import android.content.DialogInterface;
     31 import android.content.Intent;
     32 import android.content.Loader;
     33 import android.content.pm.ApplicationInfo;
     34 import android.content.pm.PackageInfo;
     35 import android.content.pm.PackageManager;
     36 import android.content.pm.PackageManager.NameNotFoundException;
     37 import android.content.pm.ResolveInfo;
     38 import android.content.pm.UserInfo;
     39 import android.content.res.Resources;
     40 import android.graphics.drawable.Drawable;
     41 import android.icu.text.ListFormatter;
     42 import android.net.INetworkStatsService;
     43 import android.net.INetworkStatsSession;
     44 import android.net.NetworkTemplate;
     45 import android.net.TrafficStats;
     46 import android.net.Uri;
     47 import android.os.AsyncTask;
     48 import android.os.BatteryStats;
     49 import android.os.Bundle;
     50 import android.os.RemoteException;
     51 import android.os.ServiceManager;
     52 import android.os.UserHandle;
     53 import android.os.UserManager;
     54 import android.provider.Settings;
     55 import android.service.notification.NotificationListenerService.Ranking;
     56 import android.support.v7.preference.Preference;
     57 import android.support.v7.preference.Preference.OnPreferenceClickListener;
     58 import android.support.v7.preference.PreferenceCategory;
     59 import android.support.v7.preference.PreferenceScreen;
     60 import android.text.TextUtils;
     61 import android.text.format.DateUtils;
     62 import android.text.format.Formatter;
     63 import android.util.Log;
     64 import android.view.LayoutInflater;
     65 import android.view.Menu;
     66 import android.view.MenuInflater;
     67 import android.view.MenuItem;
     68 import android.view.View;
     69 import android.view.View.OnClickListener;
     70 import android.view.ViewGroup;
     71 import android.webkit.IWebViewUpdateService;
     72 import android.widget.Button;
     73 import android.widget.ImageView;
     74 import android.widget.TextView;
     75 
     76 import com.android.internal.logging.MetricsProto.MetricsEvent;
     77 import com.android.internal.os.BatterySipper;
     78 import com.android.internal.os.BatteryStatsHelper;
     79 import com.android.internal.widget.LockPatternUtils;
     80 import com.android.settings.AppHeader;
     81 import com.android.settings.DeviceAdminAdd;
     82 import com.android.settings.R;
     83 import com.android.settings.SettingsActivity;
     84 import com.android.settings.SettingsPreferenceFragment;
     85 import com.android.settings.Utils;
     86 import com.android.settings.applications.PermissionsSummaryHelper.PermissionsResultCallback;
     87 import com.android.settings.datausage.AppDataUsage;
     88 import com.android.settings.datausage.DataUsageList;
     89 import com.android.settings.datausage.DataUsageSummary;
     90 import com.android.settings.fuelgauge.BatteryEntry;
     91 import com.android.settings.fuelgauge.PowerUsageDetail;
     92 import com.android.settings.notification.AppNotificationSettings;
     93 import com.android.settings.notification.NotificationBackend;
     94 import com.android.settings.notification.NotificationBackend.AppRow;
     95 import com.android.settingslib.AppItem;
     96 import com.android.settingslib.RestrictedLockUtils;
     97 import com.android.settingslib.applications.AppUtils;
     98 import com.android.settingslib.applications.ApplicationsState;
     99 import com.android.settingslib.applications.ApplicationsState.AppEntry;
    100 import com.android.settingslib.net.ChartData;
    101 import com.android.settingslib.net.ChartDataLoader;
    102 
    103 import java.lang.ref.WeakReference;
    104 import java.util.ArrayList;
    105 import java.util.HashSet;
    106 import java.util.List;
    107 
    108 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
    109 
    110 /**
    111  * Activity to display application information from Settings. This activity presents
    112  * extended information associated with a package like code, data, total size, permissions
    113  * used by the application and also the set of default launchable activities.
    114  * For system applications, an option to clear user data is displayed only if data size is > 0.
    115  * System applications that do not want clear user data do not have this option.
    116  * For non-system applications, there is no option to clear data. Instead there is an option to
    117  * uninstall the application.
    118  */
    119 public class InstalledAppDetails extends AppInfoBase
    120         implements View.OnClickListener, OnPreferenceClickListener {
    121 
    122     private static final String LOG_TAG = "InstalledAppDetails";
    123 
    124     // Menu identifiers
    125     public static final int UNINSTALL_ALL_USERS_MENU = 1;
    126     public static final int UNINSTALL_UPDATES = 2;
    127 
    128     // Result code identifiers
    129     public static final int REQUEST_UNINSTALL = 0;
    130     private static final int REQUEST_REMOVE_DEVICE_ADMIN = 1;
    131 
    132     private static final int SUB_INFO_FRAGMENT = 1;
    133 
    134     private static final int LOADER_CHART_DATA = 2;
    135 
    136     private static final int DLG_FORCE_STOP = DLG_BASE + 1;
    137     private static final int DLG_DISABLE = DLG_BASE + 2;
    138     private static final int DLG_SPECIAL_DISABLE = DLG_BASE + 3;
    139 
    140     private static final String KEY_HEADER = "header_view";
    141     private static final String KEY_NOTIFICATION = "notification_settings";
    142     private static final String KEY_STORAGE = "storage_settings";
    143     private static final String KEY_PERMISSION = "permission_settings";
    144     private static final String KEY_DATA = "data_settings";
    145     private static final String KEY_LAUNCH = "preferred_settings";
    146     private static final String KEY_BATTERY = "battery";
    147     private static final String KEY_MEMORY = "memory";
    148 
    149     private static final String NOTIFICATION_TUNER_SETTING = "show_importance_slider";
    150 
    151     private final HashSet<String> mHomePackages = new HashSet<String>();
    152 
    153     private boolean mInitialized;
    154     private boolean mShowUninstalled;
    155     private LayoutPreference mHeader;
    156     private Button mUninstallButton;
    157     private boolean mUpdatedSysApp = false;
    158     private Button mForceStopButton;
    159     private Preference mNotificationPreference;
    160     private Preference mStoragePreference;
    161     private Preference mPermissionsPreference;
    162     private Preference mLaunchPreference;
    163     private Preference mDataPreference;
    164     private Preference mMemoryPreference;
    165 
    166     private boolean mDisableAfterUninstall;
    167     // Used for updating notification preference.
    168     private final NotificationBackend mBackend = new NotificationBackend();
    169 
    170     private ChartData mChartData;
    171     private INetworkStatsSession mStatsSession;
    172 
    173     private Preference mBatteryPreference;
    174 
    175     private BatteryStatsHelper mBatteryHelper;
    176     private BatterySipper mSipper;
    177 
    178     protected ProcStatsData mStatsManager;
    179     protected ProcStatsPackageEntry mStats;
    180 
    181     private boolean handleDisableable(Button button) {
    182         boolean disableable = false;
    183         // Try to prevent the user from bricking their phone
    184         // by not allowing disabling of apps signed with the
    185         // system cert and any launcher app in the system.
    186         if (mHomePackages.contains(mAppEntry.info.packageName)
    187                 || Utils.isSystemPackage(getContext().getResources(), mPm, mPackageInfo)) {
    188             // Disable button for core system applications.
    189             button.setText(R.string.disable_text);
    190         } else if (mAppEntry.info.enabled && !isDisabledUntilUsed()) {
    191             button.setText(R.string.disable_text);
    192             disableable = true;
    193         } else {
    194             button.setText(R.string.enable_text);
    195             disableable = true;
    196         }
    197 
    198         return disableable;
    199     }
    200 
    201     private boolean isDisabledUntilUsed() {
    202         return mAppEntry.info.enabledSetting
    203                 == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
    204     }
    205 
    206     private void initUninstallButtons() {
    207         final boolean isBundled = (mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
    208         boolean enabled = true;
    209         if (isBundled) {
    210             enabled = handleDisableable(mUninstallButton);
    211         } else {
    212             if ((mPackageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) == 0
    213                     && mUserManager.getUsers().size() >= 2) {
    214                 // When we have multiple users, there is a separate menu
    215                 // to uninstall for all users.
    216                 enabled = false;
    217             }
    218             mUninstallButton.setText(R.string.uninstall_text);
    219         }
    220         // If this is a device admin, it can't be uninstalled or disabled.
    221         // We do this here so the text of the button is still set correctly.
    222         if (isBundled && mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
    223             enabled = false;
    224         }
    225 
    226         // We don't allow uninstalling DO/PO on *any* users, because if it's a system app,
    227         // "uninstall" is actually "downgrade to the system version + disable", and "downgrade"
    228         // will clear data on all users.
    229         if (isProfileOrDeviceOwner(mPackageInfo.packageName)) {
    230             enabled = false;
    231         }
    232 
    233         // Don't allow uninstalling the device provisioning package.
    234         if (Utils.isDeviceProvisioningPackage(getResources(), mAppEntry.info.packageName)) {
    235             enabled = false;
    236         }
    237 
    238         // If the uninstall intent is already queued, disable the uninstall button
    239         if (mDpm.isUninstallInQueue(mPackageName)) {
    240             enabled = false;
    241         }
    242 
    243         // Home apps need special handling.  Bundled ones we don't risk downgrading
    244         // because that can interfere with home-key resolution.  Furthermore, we
    245         // can't allow uninstallation of the only home app, and we don't want to
    246         // allow uninstallation of an explicitly preferred one -- the user can go
    247         // to Home settings and pick a different one, after which we'll permit
    248         // uninstallation of the now-not-default one.
    249         if (enabled && mHomePackages.contains(mPackageInfo.packageName)) {
    250             if (isBundled) {
    251                 enabled = false;
    252             } else {
    253                 ArrayList<ResolveInfo> homeActivities = new ArrayList<ResolveInfo>();
    254                 ComponentName currentDefaultHome  = mPm.getHomeActivities(homeActivities);
    255                 if (currentDefaultHome == null) {
    256                     // No preferred default, so permit uninstall only when
    257                     // there is more than one candidate
    258                     enabled = (mHomePackages.size() > 1);
    259                 } else {
    260                     // There is an explicit default home app -- forbid uninstall of
    261                     // that one, but permit it for installed-but-inactive ones.
    262                     enabled = !mPackageInfo.packageName.equals(currentDefaultHome.getPackageName());
    263                 }
    264             }
    265         }
    266 
    267         if (mAppsControlDisallowedBySystem) {
    268             enabled = false;
    269         }
    270 
    271         try {
    272             IWebViewUpdateService webviewUpdateService =
    273                 IWebViewUpdateService.Stub.asInterface(ServiceManager.getService("webviewupdate"));
    274             if (webviewUpdateService.isFallbackPackage(mAppEntry.info.packageName)) {
    275                 enabled = false;
    276             }
    277         } catch (RemoteException e) {
    278             throw new RuntimeException(e);
    279         }
    280 
    281         mUninstallButton.setEnabled(enabled);
    282         if (enabled) {
    283             // Register listener
    284             mUninstallButton.setOnClickListener(this);
    285         }
    286     }
    287 
    288     /** Returns if the supplied package is device owner or profile owner of at least one user */
    289     private boolean isProfileOrDeviceOwner(String packageName) {
    290         List<UserInfo> userInfos = mUserManager.getUsers();
    291         DevicePolicyManager dpm = (DevicePolicyManager)
    292                 getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
    293         if (dpm.isDeviceOwnerAppOnAnyUser(packageName)) {
    294             return true;
    295         }
    296         for (UserInfo userInfo : userInfos) {
    297             ComponentName cn = dpm.getProfileOwnerAsUser(userInfo.id);
    298             if (cn != null && cn.getPackageName().equals(packageName)) {
    299                 return true;
    300             }
    301         }
    302         return false;
    303     }
    304 
    305     /** Called when the activity is first created. */
    306     @Override
    307     public void onCreate(Bundle icicle) {
    308         super.onCreate(icicle);
    309 
    310         setHasOptionsMenu(true);
    311         addPreferencesFromResource(R.xml.installed_app_details);
    312         addDynamicPrefs();
    313 
    314         if (Utils.isBandwidthControlEnabled()) {
    315             INetworkStatsService statsService = INetworkStatsService.Stub.asInterface(
    316                     ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
    317             try {
    318                 mStatsSession = statsService.openSession();
    319             } catch (RemoteException e) {
    320                 throw new RuntimeException(e);
    321             }
    322         } else {
    323             removePreference(KEY_DATA);
    324         }
    325         mBatteryHelper = new BatteryStatsHelper(getActivity(), true);
    326     }
    327 
    328     @Override
    329     protected int getMetricsCategory() {
    330         return MetricsEvent.APPLICATIONS_INSTALLED_APP_DETAILS;
    331     }
    332 
    333     @Override
    334     public void onResume() {
    335         super.onResume();
    336         if (mFinishing) {
    337             return;
    338         }
    339         mState.requestSize(mPackageName, mUserId);
    340         AppItem app = new AppItem(mAppEntry.info.uid);
    341         app.addUid(mAppEntry.info.uid);
    342         if (mStatsSession != null) {
    343             getLoaderManager().restartLoader(LOADER_CHART_DATA,
    344                     ChartDataLoader.buildArgs(getTemplate(getContext()), app),
    345                     mDataCallbacks);
    346         }
    347         new BatteryUpdater().execute();
    348         new MemoryUpdater().execute();
    349         updateDynamicPrefs();
    350     }
    351 
    352     @Override
    353     public void onPause() {
    354         getLoaderManager().destroyLoader(LOADER_CHART_DATA);
    355         super.onPause();
    356     }
    357 
    358     @Override
    359     public void onDestroy() {
    360         TrafficStats.closeQuietly(mStatsSession);
    361         super.onDestroy();
    362     }
    363 
    364     public void onActivityCreated(Bundle savedInstanceState) {
    365         super.onActivityCreated(savedInstanceState);
    366         if (mFinishing) {
    367             return;
    368         }
    369         handleHeader();
    370 
    371         mNotificationPreference = findPreference(KEY_NOTIFICATION);
    372         mNotificationPreference.setOnPreferenceClickListener(this);
    373         mStoragePreference = findPreference(KEY_STORAGE);
    374         mStoragePreference.setOnPreferenceClickListener(this);
    375         mPermissionsPreference = findPreference(KEY_PERMISSION);
    376         mPermissionsPreference.setOnPreferenceClickListener(this);
    377         mDataPreference = findPreference(KEY_DATA);
    378         if (mDataPreference != null) {
    379             mDataPreference.setOnPreferenceClickListener(this);
    380         }
    381         mBatteryPreference = findPreference(KEY_BATTERY);
    382         mBatteryPreference.setEnabled(false);
    383         mBatteryPreference.setOnPreferenceClickListener(this);
    384         mMemoryPreference = findPreference(KEY_MEMORY);
    385         mMemoryPreference.setOnPreferenceClickListener(this);
    386 
    387         mLaunchPreference = findPreference(KEY_LAUNCH);
    388         if (mAppEntry != null && mAppEntry.info != null) {
    389             if ((mAppEntry.info.flags&ApplicationInfo.FLAG_INSTALLED) == 0 ||
    390                     !mAppEntry.info.enabled) {
    391                 mLaunchPreference.setEnabled(false);
    392             } else {
    393                 mLaunchPreference.setOnPreferenceClickListener(this);
    394             }
    395         } else {
    396             mLaunchPreference.setEnabled(false);
    397         }
    398     }
    399 
    400     private void handleHeader() {
    401         mHeader = (LayoutPreference) findPreference(KEY_HEADER);
    402 
    403         // Get Control button panel
    404         View btnPanel = mHeader.findViewById(R.id.control_buttons_panel);
    405         mForceStopButton = (Button) btnPanel.findViewById(R.id.right_button);
    406         mForceStopButton.setText(R.string.force_stop);
    407         mUninstallButton = (Button) btnPanel.findViewById(R.id.left_button);
    408         mForceStopButton.setEnabled(false);
    409 
    410         View gear = mHeader.findViewById(R.id.gear);
    411         Intent i = new Intent(Intent.ACTION_APPLICATION_PREFERENCES);
    412         i.setPackage(mPackageName);
    413         final Intent intent = resolveIntent(i);
    414         if (intent != null) {
    415             gear.setVisibility(View.VISIBLE);
    416             gear.setOnClickListener(new OnClickListener() {
    417                 @Override
    418                 public void onClick(View v) {
    419                     startActivity(intent);
    420                 }
    421             });
    422         } else {
    423             gear.setVisibility(View.GONE);
    424         }
    425     }
    426 
    427     private Intent resolveIntent(Intent i) {
    428         ResolveInfo result = getContext().getPackageManager().resolveActivity(i, 0);
    429         return result != null ? new Intent(i.getAction())
    430                 .setClassName(result.activityInfo.packageName, result.activityInfo.name) : null;
    431     }
    432 
    433     @Override
    434     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    435         menu.add(0, UNINSTALL_UPDATES, 0, R.string.app_factory_reset)
    436                 .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
    437         menu.add(0, UNINSTALL_ALL_USERS_MENU, 1, R.string.uninstall_all_users_text)
    438                 .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
    439     }
    440 
    441     @Override
    442     public void onPrepareOptionsMenu(Menu menu) {
    443         if (mFinishing) {
    444             return;
    445         }
    446         boolean showIt = true;
    447         if (mUpdatedSysApp) {
    448             showIt = false;
    449         } else if (mAppEntry == null) {
    450             showIt = false;
    451         } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
    452             showIt = false;
    453         } else if (mPackageInfo == null || mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
    454             showIt = false;
    455         } else if (UserHandle.myUserId() != 0) {
    456             showIt = false;
    457         } else if (mUserManager.getUsers().size() < 2) {
    458             showIt = false;
    459         }
    460         menu.findItem(UNINSTALL_ALL_USERS_MENU).setVisible(showIt);
    461         mUpdatedSysApp = (mAppEntry.info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
    462         MenuItem uninstallUpdatesItem = menu.findItem(UNINSTALL_UPDATES);
    463         uninstallUpdatesItem.setVisible(mUpdatedSysApp && !mAppsControlDisallowedBySystem);
    464         if (uninstallUpdatesItem.isVisible()) {
    465             RestrictedLockUtils.setMenuItemAsDisabledByAdmin(getActivity(),
    466                     uninstallUpdatesItem, mAppsControlDisallowedAdmin);
    467         }
    468     }
    469 
    470     @Override
    471     public boolean onOptionsItemSelected(MenuItem item) {
    472         switch (item.getItemId()) {
    473             case UNINSTALL_ALL_USERS_MENU:
    474                 uninstallPkg(mAppEntry.info.packageName, true, false);
    475                 return true;
    476             case UNINSTALL_UPDATES:
    477                 uninstallPkg(mAppEntry.info.packageName, false, false);
    478                 return true;
    479         }
    480         return false;
    481     }
    482 
    483     @Override
    484     public void onActivityResult(int requestCode, int resultCode, Intent data) {
    485         super.onActivityResult(requestCode, resultCode, data);
    486         switch (requestCode) {
    487             case REQUEST_UNINSTALL:
    488                 if (mDisableAfterUninstall) {
    489                     mDisableAfterUninstall = false;
    490                     new DisableChanger(this, mAppEntry.info,
    491                             PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER)
    492                             .execute((Object)null);
    493                 }
    494                 // continue with following operations
    495             case REQUEST_REMOVE_DEVICE_ADMIN:
    496                 if (!refreshUi()) {
    497                     setIntentAndFinish(true, true);
    498                 } else {
    499                     startListeningToPackageRemove();
    500                 }
    501                 break;
    502         }
    503     }
    504 
    505     // Utility method to set application label and icon.
    506     private void setAppLabelAndIcon(PackageInfo pkgInfo) {
    507         final View appSnippet = mHeader.findViewById(R.id.app_snippet);
    508         mState.ensureIcon(mAppEntry);
    509         setupAppSnippet(appSnippet, mAppEntry.label, mAppEntry.icon,
    510                 pkgInfo != null ? pkgInfo.versionName : null);
    511     }
    512 
    513     private boolean signaturesMatch(String pkg1, String pkg2) {
    514         if (pkg1 != null && pkg2 != null) {
    515             try {
    516                 final int match = mPm.checkSignatures(pkg1, pkg2);
    517                 if (match >= PackageManager.SIGNATURE_MATCH) {
    518                     return true;
    519                 }
    520             } catch (Exception e) {
    521                 // e.g. named alternate package not found during lookup;
    522                 // this is an expected case sometimes
    523             }
    524         }
    525         return false;
    526     }
    527 
    528     @Override
    529     protected boolean refreshUi() {
    530         retrieveAppEntry();
    531         if (mAppEntry == null) {
    532             return false; // onCreate must have failed, make sure to exit
    533         }
    534 
    535         if (mPackageInfo == null) {
    536             return false; // onCreate must have failed, make sure to exit
    537         }
    538 
    539         // Get list of "home" apps and trace through any meta-data references
    540         List<ResolveInfo> homeActivities = new ArrayList<ResolveInfo>();
    541         mPm.getHomeActivities(homeActivities);
    542         mHomePackages.clear();
    543         for (int i = 0; i< homeActivities.size(); i++) {
    544             ResolveInfo ri = homeActivities.get(i);
    545             final String activityPkg = ri.activityInfo.packageName;
    546             mHomePackages.add(activityPkg);
    547 
    548             // Also make sure to include anything proxying for the home app
    549             final Bundle metadata = ri.activityInfo.metaData;
    550             if (metadata != null) {
    551                 final String metaPkg = metadata.getString(ActivityManager.META_HOME_ALTERNATE);
    552                 if (signaturesMatch(metaPkg, activityPkg)) {
    553                     mHomePackages.add(metaPkg);
    554                 }
    555             }
    556         }
    557 
    558         checkForceStop();
    559         setAppLabelAndIcon(mPackageInfo);
    560         initUninstallButtons();
    561 
    562         // Update the preference summaries.
    563         Activity context = getActivity();
    564         mStoragePreference.setSummary(AppStorageSettings.getSummary(mAppEntry, context));
    565 
    566         PermissionsSummaryHelper.getPermissionSummary(getContext(),
    567                 mPackageName, mPermissionCallback);
    568         mLaunchPreference.setSummary(AppUtils.getLaunchByDefaultSummary(mAppEntry, mUsbManager,
    569                 mPm, context));
    570         mNotificationPreference.setSummary(getNotificationSummary(mAppEntry, context,
    571                 mBackend));
    572         if (mDataPreference != null) {
    573             mDataPreference.setSummary(getDataSummary());
    574         }
    575 
    576         updateBattery();
    577 
    578         if (!mInitialized) {
    579             // First time init: are we displaying an uninstalled app?
    580             mInitialized = true;
    581             mShowUninstalled = (mAppEntry.info.flags&ApplicationInfo.FLAG_INSTALLED) == 0;
    582         } else {
    583             // All other times: if the app no longer exists then we want
    584             // to go away.
    585             try {
    586                 ApplicationInfo ainfo = context.getPackageManager().getApplicationInfo(
    587                         mAppEntry.info.packageName, PackageManager.GET_UNINSTALLED_PACKAGES
    588                         | PackageManager.GET_DISABLED_COMPONENTS);
    589                 if (!mShowUninstalled) {
    590                     // If we did not start out with the app uninstalled, then
    591                     // it transitioning to the uninstalled state for the current
    592                     // user means we should go away as well.
    593                     return (ainfo.flags&ApplicationInfo.FLAG_INSTALLED) != 0;
    594                 }
    595             } catch (NameNotFoundException e) {
    596                 return false;
    597             }
    598         }
    599 
    600         return true;
    601     }
    602 
    603     private void updateBattery() {
    604         if (mSipper != null) {
    605             mBatteryPreference.setEnabled(true);
    606             int dischargeAmount = mBatteryHelper.getStats().getDischargeAmount(
    607                     BatteryStats.STATS_SINCE_CHARGED);
    608             final int percentOfMax = (int) ((mSipper.totalPowerMah)
    609                     / mBatteryHelper.getTotalPower() * dischargeAmount + .5f);
    610             mBatteryPreference.setSummary(getString(R.string.battery_summary, percentOfMax));
    611         } else {
    612             mBatteryPreference.setEnabled(false);
    613             mBatteryPreference.setSummary(getString(R.string.no_battery_summary));
    614         }
    615     }
    616 
    617     private CharSequence getDataSummary() {
    618         if (mChartData != null) {
    619             long totalBytes = mChartData.detail.getTotalBytes();
    620             if (totalBytes == 0) {
    621                 return getString(R.string.no_data_usage);
    622             }
    623             Context context = getActivity();
    624             return getString(R.string.data_summary_format,
    625                     Formatter.formatFileSize(context, totalBytes),
    626                     DateUtils.formatDateTime(context, mChartData.detail.getStart(),
    627                             DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH));
    628         }
    629         return getString(R.string.computing_size);
    630     }
    631 
    632     @Override
    633     protected AlertDialog createDialog(int id, int errorCode) {
    634         switch (id) {
    635             case DLG_DISABLE:
    636                 return new AlertDialog.Builder(getActivity())
    637                         .setMessage(getActivity().getText(R.string.app_disable_dlg_text))
    638                         .setPositiveButton(R.string.app_disable_dlg_positive,
    639                                 new DialogInterface.OnClickListener() {
    640                             public void onClick(DialogInterface dialog, int which) {
    641                                 // Disable the app
    642                                 new DisableChanger(InstalledAppDetails.this, mAppEntry.info,
    643                                         PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER)
    644                                 .execute((Object)null);
    645                             }
    646                         })
    647                         .setNegativeButton(R.string.dlg_cancel, null)
    648                         .create();
    649             case DLG_SPECIAL_DISABLE:
    650                 return new AlertDialog.Builder(getActivity())
    651                         .setMessage(getActivity().getText(R.string.app_disable_dlg_text))
    652                         .setPositiveButton(R.string.app_disable_dlg_positive,
    653                                 new DialogInterface.OnClickListener() {
    654                             public void onClick(DialogInterface dialog, int which) {
    655                                 // Disable the app and ask for uninstall
    656                                 uninstallPkg(mAppEntry.info.packageName,
    657                                         false, true);
    658                             }
    659                         })
    660                         .setNegativeButton(R.string.dlg_cancel, null)
    661                         .create();
    662             case DLG_FORCE_STOP:
    663                 return new AlertDialog.Builder(getActivity())
    664                         .setTitle(getActivity().getText(R.string.force_stop_dlg_title))
    665                         .setMessage(getActivity().getText(R.string.force_stop_dlg_text))
    666                         .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
    667                             public void onClick(DialogInterface dialog, int which) {
    668                                 // Force stop
    669                                 forceStopPackage(mAppEntry.info.packageName);
    670                             }
    671                         })
    672                         .setNegativeButton(R.string.dlg_cancel, null)
    673                         .create();
    674         }
    675         return null;
    676     }
    677 
    678     private void uninstallPkg(String packageName, boolean allUsers, boolean andDisable) {
    679         stopListeningToPackageRemove();
    680          // Create new intent to launch Uninstaller activity
    681         Uri packageURI = Uri.parse("package:"+packageName);
    682         Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageURI);
    683         uninstallIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, allUsers);
    684         startActivityForResult(uninstallIntent, REQUEST_UNINSTALL);
    685         mDisableAfterUninstall = andDisable;
    686     }
    687 
    688     private void forceStopPackage(String pkgName) {
    689         ActivityManager am = (ActivityManager) getActivity().getSystemService(
    690                 Context.ACTIVITY_SERVICE);
    691         am.forceStopPackage(pkgName);
    692         int userId = UserHandle.getUserId(mAppEntry.info.uid);
    693         mState.invalidatePackage(pkgName, userId);
    694         ApplicationsState.AppEntry newEnt = mState.getEntry(pkgName, userId);
    695         if (newEnt != null) {
    696             mAppEntry = newEnt;
    697         }
    698         checkForceStop();
    699     }
    700 
    701     private void updateForceStopButton(boolean enabled) {
    702         if (mAppsControlDisallowedBySystem) {
    703             mForceStopButton.setEnabled(false);
    704         } else {
    705             mForceStopButton.setEnabled(enabled);
    706             mForceStopButton.setOnClickListener(InstalledAppDetails.this);
    707         }
    708     }
    709 
    710     private void checkForceStop() {
    711         if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
    712             // User can't force stop device admin.
    713             updateForceStopButton(false);
    714         } else if ((mAppEntry.info.flags&ApplicationInfo.FLAG_STOPPED) == 0) {
    715             // If the app isn't explicitly stopped, then always show the
    716             // force stop button.
    717             updateForceStopButton(true);
    718         } else {
    719             Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART,
    720                     Uri.fromParts("package", mAppEntry.info.packageName, null));
    721             intent.putExtra(Intent.EXTRA_PACKAGES, new String[] { mAppEntry.info.packageName });
    722             intent.putExtra(Intent.EXTRA_UID, mAppEntry.info.uid);
    723             intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(mAppEntry.info.uid));
    724             getActivity().sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
    725                     mCheckKillProcessesReceiver, null, Activity.RESULT_CANCELED, null, null);
    726         }
    727     }
    728 
    729     private void startManagePermissionsActivity() {
    730         // start new activity to manage app permissions
    731         Intent intent = new Intent(Intent.ACTION_MANAGE_APP_PERMISSIONS);
    732         intent.putExtra(Intent.EXTRA_PACKAGE_NAME, mAppEntry.info.packageName);
    733         intent.putExtra(AppHeader.EXTRA_HIDE_INFO_BUTTON, true);
    734         try {
    735             getActivity().startActivityForResult(intent, SUB_INFO_FRAGMENT);
    736         } catch (ActivityNotFoundException e) {
    737             Log.w(LOG_TAG, "No app can handle android.intent.action.MANAGE_APP_PERMISSIONS");
    738         }
    739     }
    740 
    741     private void startAppInfoFragment(Class<?> fragment, CharSequence title) {
    742         startAppInfoFragment(fragment, title, this, mAppEntry);
    743     }
    744 
    745     public static void startAppInfoFragment(Class<?> fragment, CharSequence title,
    746             SettingsPreferenceFragment caller, AppEntry appEntry) {
    747         // start new fragment to display extended information
    748         Bundle args = new Bundle();
    749         args.putString(ARG_PACKAGE_NAME, appEntry.info.packageName);
    750         args.putInt(ARG_PACKAGE_UID, appEntry.info.uid);
    751         args.putBoolean(AppHeader.EXTRA_HIDE_INFO_BUTTON, true);
    752 
    753         SettingsActivity sa = (SettingsActivity) caller.getActivity();
    754         sa.startPreferencePanel(fragment.getName(), args, -1, title, caller, SUB_INFO_FRAGMENT);
    755     }
    756 
    757     /*
    758      * Method implementing functionality of buttons clicked
    759      * @see android.view.View.OnClickListener#onClick(android.view.View)
    760      */
    761     public void onClick(View v) {
    762         if (mAppEntry == null) {
    763             setIntentAndFinish(true, true);
    764             return;
    765         }
    766         String packageName = mAppEntry.info.packageName;
    767         if (v == mUninstallButton) {
    768             if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
    769                 stopListeningToPackageRemove();
    770                 Activity activity = getActivity();
    771                 Intent uninstallDAIntent = new Intent(activity, DeviceAdminAdd.class);
    772                 uninstallDAIntent.putExtra(DeviceAdminAdd.EXTRA_DEVICE_ADMIN_PACKAGE_NAME,
    773                         mPackageName);
    774                 activity.startActivityForResult(uninstallDAIntent, REQUEST_REMOVE_DEVICE_ADMIN);
    775                 return;
    776             }
    777             EnforcedAdmin admin = RestrictedLockUtils.checkIfUninstallBlocked(getActivity(),
    778                     packageName, mUserId);
    779             boolean uninstallBlockedBySystem = mAppsControlDisallowedBySystem ||
    780                     RestrictedLockUtils.hasBaseUserRestriction(getActivity(), packageName, mUserId);
    781             if (admin != null && !uninstallBlockedBySystem) {
    782                 RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getActivity(), admin);
    783             } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
    784                 if (mAppEntry.info.enabled && !isDisabledUntilUsed()) {
    785                     // If the system app has an update and this is the only user on the device,
    786                     // then offer to downgrade the app, otherwise only offer to disable the
    787                     // app for this user.
    788                     if (mUpdatedSysApp && isSingleUser()) {
    789                         showDialogInner(DLG_SPECIAL_DISABLE, 0);
    790                     } else {
    791                         showDialogInner(DLG_DISABLE, 0);
    792                     }
    793                 } else {
    794                     new DisableChanger(this, mAppEntry.info,
    795                             PackageManager.COMPONENT_ENABLED_STATE_DEFAULT)
    796                                     .execute((Object) null);
    797                 }
    798             } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_INSTALLED) == 0) {
    799                 uninstallPkg(packageName, true, false);
    800             } else {
    801                 uninstallPkg(packageName, false, false);
    802             }
    803         } else if (v == mForceStopButton) {
    804             if (mAppsControlDisallowedAdmin != null && !mAppsControlDisallowedBySystem) {
    805                 RestrictedLockUtils.sendShowAdminSupportDetailsIntent(
    806                         getActivity(), mAppsControlDisallowedAdmin);
    807             } else {
    808                 showDialogInner(DLG_FORCE_STOP, 0);
    809                 //forceStopPackage(mAppInfo.packageName);
    810             }
    811         }
    812     }
    813 
    814     /** Returns whether there is only one user on this device, not including the system-only user */
    815     private boolean isSingleUser() {
    816         final int userCount = mUserManager.getUserCount();
    817         return userCount == 1
    818                 || (mUserManager.isSplitSystemUser() && userCount == 2);
    819     }
    820 
    821     @Override
    822     public boolean onPreferenceClick(Preference preference) {
    823         if (preference == mStoragePreference) {
    824             startAppInfoFragment(AppStorageSettings.class, mStoragePreference.getTitle());
    825         } else if (preference == mNotificationPreference) {
    826             startAppInfoFragment(AppNotificationSettings.class,
    827                     getString(R.string.app_notifications_title));
    828         } else if (preference == mPermissionsPreference) {
    829             startManagePermissionsActivity();
    830         } else if (preference == mLaunchPreference) {
    831             startAppInfoFragment(AppLaunchSettings.class, mLaunchPreference.getTitle());
    832         } else if (preference == mMemoryPreference) {
    833             ProcessStatsBase.launchMemoryDetail((SettingsActivity) getActivity(),
    834                     mStatsManager.getMemInfo(), mStats, false);
    835         } else if (preference == mDataPreference) {
    836             startAppInfoFragment(AppDataUsage.class, getString(R.string.app_data_usage));
    837         } else if (preference == mBatteryPreference) {
    838             BatteryEntry entry = new BatteryEntry(getActivity(), null, mUserManager, mSipper);
    839             PowerUsageDetail.startBatteryDetailPage((SettingsActivity) getActivity(),
    840                     mBatteryHelper, BatteryStats.STATS_SINCE_CHARGED, entry, true, false);
    841         } else {
    842             return false;
    843         }
    844         return true;
    845     }
    846 
    847     private void addDynamicPrefs() {
    848         if (Utils.isManagedProfile(UserManager.get(getContext()))) {
    849             return;
    850         }
    851         final PreferenceScreen screen = getPreferenceScreen();
    852         if (DefaultHomePreference.hasHomePreference(mPackageName, getContext())) {
    853             screen.addPreference(new ShortcutPreference(getPrefContext(),
    854                     AdvancedAppSettings.class, "default_home", R.string.home_app,
    855                     R.string.configure_apps));
    856         }
    857         if (DefaultBrowserPreference.hasBrowserPreference(mPackageName, getContext())) {
    858             screen.addPreference(new ShortcutPreference(getPrefContext(),
    859                     AdvancedAppSettings.class, "default_browser", R.string.default_browser_title,
    860                     R.string.configure_apps));
    861         }
    862         if (DefaultPhonePreference.hasPhonePreference(mPackageName, getContext())) {
    863             screen.addPreference(new ShortcutPreference(getPrefContext(),
    864                     AdvancedAppSettings.class, "default_phone_app", R.string.default_phone_title,
    865                     R.string.configure_apps));
    866         }
    867         if (DefaultEmergencyPreference.hasEmergencyPreference(mPackageName, getContext())) {
    868             screen.addPreference(new ShortcutPreference(getPrefContext(),
    869                     AdvancedAppSettings.class, "default_emergency_app",
    870                     R.string.default_emergency_app, R.string.configure_apps));
    871         }
    872         if (DefaultSmsPreference.hasSmsPreference(mPackageName, getContext())) {
    873             screen.addPreference(new ShortcutPreference(getPrefContext(),
    874                     AdvancedAppSettings.class, "default_sms_app", R.string.sms_application_title,
    875                     R.string.configure_apps));
    876         }
    877         boolean hasDrawOverOtherApps = hasPermission(permission.SYSTEM_ALERT_WINDOW);
    878         boolean hasWriteSettings = hasPermission(permission.WRITE_SETTINGS);
    879         if (hasDrawOverOtherApps || hasWriteSettings) {
    880             PreferenceCategory category = new PreferenceCategory(getPrefContext());
    881             category.setTitle(R.string.advanced_apps);
    882             screen.addPreference(category);
    883 
    884             if (hasDrawOverOtherApps) {
    885                 Preference pref = new Preference(getPrefContext());
    886                 pref.setTitle(R.string.draw_overlay);
    887                 pref.setKey("system_alert_window");
    888                 pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
    889                     @Override
    890                     public boolean onPreferenceClick(Preference preference) {
    891                         startAppInfoFragment(DrawOverlayDetails.class,
    892                                 getString(R.string.draw_overlay));
    893                         return true;
    894                     }
    895                 });
    896                 category.addPreference(pref);
    897             }
    898             if (hasWriteSettings) {
    899                 Preference pref = new Preference(getPrefContext());
    900                 pref.setTitle(R.string.write_settings);
    901                 pref.setKey("write_settings_apps");
    902                 pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
    903                     @Override
    904                     public boolean onPreferenceClick(Preference preference) {
    905                         startAppInfoFragment(WriteSettingsDetails.class,
    906                                 getString(R.string.write_settings));
    907                         return true;
    908                     }
    909                 });
    910                 category.addPreference(pref);
    911             }
    912         }
    913 
    914         addAppInstallerInfoPref(screen);
    915     }
    916 
    917     private void addAppInstallerInfoPref(PreferenceScreen screen) {
    918         String installerPackageName = null;
    919         try {
    920             installerPackageName =
    921                     getContext().getPackageManager().getInstallerPackageName(mPackageName);
    922         } catch (IllegalArgumentException e) {
    923             Log.e(TAG, "Exception while retrieving the package installer of " + mPackageName, e);
    924         }
    925         if (installerPackageName == null) {
    926             return;
    927         }
    928         final CharSequence installerLabel = Utils.getApplicationLabel(getContext(),
    929                 installerPackageName);
    930         if (installerLabel == null) {
    931             return;
    932         }
    933         PreferenceCategory category = new PreferenceCategory(getPrefContext());
    934         category.setTitle(R.string.app_install_details_group_title);
    935         screen.addPreference(category);
    936         Preference pref = new Preference(getPrefContext());
    937         pref.setTitle(R.string.app_install_details_title);
    938         pref.setKey("app_info_store");
    939         pref.setSummary(getString(R.string.app_install_details_summary, installerLabel));
    940         final Intent intent = new Intent(Intent.ACTION_SHOW_APP_INFO)
    941                 .setPackage(installerPackageName);
    942         final Intent result = resolveIntent(intent);
    943         if (result != null) {
    944             result.putExtra(Intent.EXTRA_PACKAGE_NAME, mPackageName);
    945             pref.setIntent(result);
    946         } else {
    947             pref.setEnabled(false);
    948         }
    949         category.addPreference(pref);
    950     }
    951 
    952     private boolean hasPermission(String permission) {
    953         if (mPackageInfo == null || mPackageInfo.requestedPermissions == null) {
    954             return false;
    955         }
    956         for (int i = 0; i < mPackageInfo.requestedPermissions.length; i++) {
    957             if (mPackageInfo.requestedPermissions[i].equals(permission)) {
    958                 return true;
    959             }
    960         }
    961         return false;
    962     }
    963 
    964     private void updateDynamicPrefs() {
    965         Preference pref = findPreference("default_home");
    966         if (pref != null) {
    967             pref.setSummary(DefaultHomePreference.isHomeDefault(mPackageName, getContext())
    968                     ? R.string.yes : R.string.no);
    969         }
    970         pref = findPreference("default_browser");
    971         if (pref != null) {
    972             pref.setSummary(DefaultBrowserPreference.isBrowserDefault(mPackageName, getContext())
    973                     ? R.string.yes : R.string.no);
    974         }
    975         pref = findPreference("default_phone_app");
    976         if (pref != null) {
    977             pref.setSummary(DefaultPhonePreference.isPhoneDefault(mPackageName, getContext())
    978                     ? R.string.yes : R.string.no);
    979         }
    980         pref = findPreference("default_emergency_app");
    981         if (pref != null) {
    982             pref.setSummary(DefaultEmergencyPreference.isEmergencyDefault(mPackageName,
    983                     getContext()) ? R.string.yes : R.string.no);
    984         }
    985         pref = findPreference("default_sms_app");
    986         if (pref != null) {
    987             pref.setSummary(DefaultSmsPreference.isSmsDefault(mPackageName, getContext())
    988                     ? R.string.yes : R.string.no);
    989         }
    990         pref = findPreference("system_alert_window");
    991         if (pref != null) {
    992             pref.setSummary(DrawOverlayDetails.getSummary(getContext(), mAppEntry));
    993         }
    994         pref = findPreference("write_settings_apps");
    995         if (pref != null) {
    996             pref.setSummary(WriteSettingsDetails.getSummary(getContext(), mAppEntry));
    997         }
    998     }
    999 
   1000     public static void setupAppSnippet(View appSnippet, CharSequence label, Drawable icon,
   1001             CharSequence versionName) {
   1002         LayoutInflater.from(appSnippet.getContext()).inflate(R.layout.widget_text_views,
   1003                 (ViewGroup) appSnippet.findViewById(android.R.id.widget_frame));
   1004 
   1005         ImageView iconView = (ImageView) appSnippet.findViewById(android.R.id.icon);
   1006         iconView.setImageDrawable(icon);
   1007         // Set application name.
   1008         TextView labelView = (TextView) appSnippet.findViewById(android.R.id.title);
   1009         labelView.setText(label);
   1010         // Version number of application
   1011         TextView appVersion = (TextView) appSnippet.findViewById(R.id.widget_text1);
   1012 
   1013         if (!TextUtils.isEmpty(versionName)) {
   1014             appVersion.setSelected(true);
   1015             appVersion.setVisibility(View.VISIBLE);
   1016             appVersion.setText(appSnippet.getContext().getString(R.string.version_text,
   1017                     String.valueOf(versionName)));
   1018         } else {
   1019             appVersion.setVisibility(View.INVISIBLE);
   1020         }
   1021     }
   1022 
   1023     public static NetworkTemplate getTemplate(Context context) {
   1024         if (DataUsageList.hasReadyMobileRadio(context)) {
   1025             return NetworkTemplate.buildTemplateMobileWildcard();
   1026         }
   1027         if (DataUsageSummary.hasWifiRadio(context)) {
   1028             return NetworkTemplate.buildTemplateWifiWildcard();
   1029         }
   1030         return NetworkTemplate.buildTemplateEthernet();
   1031     }
   1032 
   1033     public static CharSequence getNotificationSummary(AppEntry appEntry, Context context) {
   1034         return getNotificationSummary(appEntry, context, new NotificationBackend());
   1035     }
   1036 
   1037     public static CharSequence getNotificationSummary(AppEntry appEntry, Context context,
   1038             NotificationBackend backend) {
   1039         AppRow appRow = backend.loadAppRow(context, context.getPackageManager(), appEntry.info);
   1040         return getNotificationSummary(appRow, context);
   1041     }
   1042 
   1043     public static CharSequence getNotificationSummary(AppRow appRow, Context context) {
   1044         boolean showSlider = Settings.Secure.getInt(
   1045                 context.getContentResolver(), NOTIFICATION_TUNER_SETTING, 0) == 1;
   1046         List<String> summaryAttributes = new ArrayList<>();
   1047         StringBuffer summary = new StringBuffer();
   1048         if (showSlider) {
   1049             if (appRow.appImportance != Ranking.IMPORTANCE_UNSPECIFIED) {
   1050                 summaryAttributes.add(context.getString(
   1051                         R.string.notification_summary_level, appRow.appImportance));
   1052             }
   1053         } else {
   1054             if (appRow.banned) {
   1055                 summaryAttributes.add(context.getString(R.string.notifications_disabled));
   1056             } else if (appRow.appImportance > Ranking.IMPORTANCE_NONE
   1057                     && appRow.appImportance < Ranking.IMPORTANCE_DEFAULT) {
   1058                 summaryAttributes.add(context.getString(R.string.notifications_silenced));
   1059             }
   1060         }
   1061         final boolean lockscreenSecure = new LockPatternUtils(context).isSecure(
   1062                 UserHandle.myUserId());
   1063         if (lockscreenSecure) {
   1064             if (appRow.appVisOverride == Notification.VISIBILITY_PRIVATE) {
   1065                 summaryAttributes.add(context.getString(R.string.notifications_redacted));
   1066             } else if (appRow.appVisOverride == Notification.VISIBILITY_SECRET) {
   1067                 summaryAttributes.add(context.getString(R.string.notifications_hidden));
   1068             }
   1069         }
   1070         if (appRow.appBypassDnd) {
   1071             summaryAttributes.add(context.getString(R.string.notifications_priority));
   1072         }
   1073         final int N = summaryAttributes.size();
   1074         for (int i = 0; i < N; i++) {
   1075             if (i > 0) {
   1076                 summary.append(context.getString(R.string.notifications_summary_divider));
   1077             }
   1078             summary.append(summaryAttributes.get(i));
   1079         }
   1080         return summary.toString();
   1081     }
   1082 
   1083     @Override
   1084     protected void onPackageRemoved() {
   1085         getActivity().finishActivity(SUB_INFO_FRAGMENT);
   1086         super.onPackageRemoved();
   1087     }
   1088 
   1089     private class MemoryUpdater extends AsyncTask<Void, Void, ProcStatsPackageEntry> {
   1090 
   1091         @Override
   1092         protected ProcStatsPackageEntry doInBackground(Void... params) {
   1093             if (getActivity() == null) {
   1094                 return null;
   1095             }
   1096             if (mPackageInfo == null) {
   1097                 return null;
   1098             }
   1099             if (mStatsManager == null) {
   1100                 mStatsManager = new ProcStatsData(getActivity(), false);
   1101                 mStatsManager.setDuration(ProcessStatsBase.sDurations[0]);
   1102             }
   1103             mStatsManager.refreshStats(true);
   1104             for (ProcStatsPackageEntry pkgEntry : mStatsManager.getEntries()) {
   1105                 for (ProcStatsEntry entry : pkgEntry.mEntries) {
   1106                     if (entry.mUid == mPackageInfo.applicationInfo.uid) {
   1107                         pkgEntry.updateMetrics();
   1108                         return pkgEntry;
   1109                     }
   1110                 }
   1111             }
   1112             return null;
   1113         }
   1114 
   1115         @Override
   1116         protected void onPostExecute(ProcStatsPackageEntry entry) {
   1117             if (getActivity() == null) {
   1118                 return;
   1119             }
   1120             if (entry != null) {
   1121                 mStats = entry;
   1122                 mMemoryPreference.setEnabled(true);
   1123                 double amount = Math.max(entry.mRunWeight, entry.mBgWeight)
   1124                         * mStatsManager.getMemInfo().weightToRam;
   1125                 mMemoryPreference.setSummary(getString(R.string.memory_use_summary,
   1126                         Formatter.formatShortFileSize(getContext(), (long) amount)));
   1127             } else {
   1128                 mMemoryPreference.setEnabled(false);
   1129                 mMemoryPreference.setSummary(getString(R.string.no_memory_use_summary));
   1130             }
   1131         }
   1132 
   1133     }
   1134 
   1135     private class BatteryUpdater extends AsyncTask<Void, Void, Void> {
   1136         @Override
   1137         protected Void doInBackground(Void... params) {
   1138             mBatteryHelper.create((Bundle) null);
   1139             mBatteryHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED,
   1140                     mUserManager.getUserProfiles());
   1141             List<BatterySipper> usageList = mBatteryHelper.getUsageList();
   1142             final int N = usageList.size();
   1143             for (int i = 0; i < N; i++) {
   1144                 BatterySipper sipper = usageList.get(i);
   1145                 if (sipper.getUid() == mPackageInfo.applicationInfo.uid) {
   1146                     mSipper = sipper;
   1147                     break;
   1148                 }
   1149             }
   1150             return null;
   1151         }
   1152 
   1153         @Override
   1154         protected void onPostExecute(Void result) {
   1155             if (getActivity() == null) {
   1156                 return;
   1157             }
   1158             refreshUi();
   1159         }
   1160     }
   1161 
   1162     private static class DisableChanger extends AsyncTask<Object, Object, Object> {
   1163         final PackageManager mPm;
   1164         final WeakReference<InstalledAppDetails> mActivity;
   1165         final ApplicationInfo mInfo;
   1166         final int mState;
   1167 
   1168         DisableChanger(InstalledAppDetails activity, ApplicationInfo info, int state) {
   1169             mPm = activity.mPm;
   1170             mActivity = new WeakReference<InstalledAppDetails>(activity);
   1171             mInfo = info;
   1172             mState = state;
   1173         }
   1174 
   1175         @Override
   1176         protected Object doInBackground(Object... params) {
   1177             mPm.setApplicationEnabledSetting(mInfo.packageName, mState, 0);
   1178             return null;
   1179         }
   1180     }
   1181 
   1182     private final LoaderCallbacks<ChartData> mDataCallbacks = new LoaderCallbacks<ChartData>() {
   1183 
   1184         @Override
   1185         public Loader<ChartData> onCreateLoader(int id, Bundle args) {
   1186             return new ChartDataLoader(getActivity(), mStatsSession, args);
   1187         }
   1188 
   1189         @Override
   1190         public void onLoadFinished(Loader<ChartData> loader, ChartData data) {
   1191             mChartData = data;
   1192             mDataPreference.setSummary(getDataSummary());
   1193         }
   1194 
   1195         @Override
   1196         public void onLoaderReset(Loader<ChartData> loader) {
   1197             // Leave last result.
   1198         }
   1199     };
   1200 
   1201     private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() {
   1202         @Override
   1203         public void onReceive(Context context, Intent intent) {
   1204             updateForceStopButton(getResultCode() != Activity.RESULT_CANCELED);
   1205         }
   1206     };
   1207 
   1208     private final PermissionsResultCallback mPermissionCallback
   1209             = new PermissionsResultCallback() {
   1210         @Override
   1211         public void onPermissionSummaryResult(int standardGrantedPermissionCount,
   1212                 int requestedPermissionCount, int additionalGrantedPermissionCount,
   1213                 List<CharSequence> grantedGroupLabels) {
   1214             if (getActivity() == null) {
   1215                 return;
   1216             }
   1217             final Resources res = getResources();
   1218             CharSequence summary = null;
   1219 
   1220             if (requestedPermissionCount == 0) {
   1221                 summary = res.getString(
   1222                         R.string.runtime_permissions_summary_no_permissions_requested);
   1223                 mPermissionsPreference.setOnPreferenceClickListener(null);
   1224                 mPermissionsPreference.setEnabled(false);
   1225             } else {
   1226                 final ArrayList<CharSequence> list = new ArrayList<>(grantedGroupLabels);
   1227                 if (additionalGrantedPermissionCount > 0) {
   1228                     // N additional permissions.
   1229                     list.add(res.getQuantityString(
   1230                             R.plurals.runtime_permissions_additional_count,
   1231                             additionalGrantedPermissionCount, additionalGrantedPermissionCount));
   1232                 }
   1233                 if (list.size() == 0) {
   1234                     summary = res.getString(
   1235                             R.string.runtime_permissions_summary_no_permissions_granted);
   1236                 } else {
   1237                     summary = ListFormatter.getInstance().format(list);
   1238                 }
   1239                 mPermissionsPreference.setOnPreferenceClickListener(InstalledAppDetails.this);
   1240                 mPermissionsPreference.setEnabled(true);
   1241             }
   1242             mPermissionsPreference.setSummary(summary);
   1243         }
   1244     };
   1245 }
   1246