2 * Copyright (C) 2007 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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
17 package com.android.settings.applications;
19 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
21 import android.Manifest.permission;
22 import android.app.Activity;
23 import android.app.ActivityManager;
24 import android.app.AlertDialog;
25 import android.app.LoaderManager;
26 import android.app.LoaderManager.LoaderCallbacks;
27 import android.app.admin.DevicePolicyManager;
28 import android.content.ActivityNotFoundException;
29 import android.content.BroadcastReceiver;
30 import android.content.ComponentName;
31 import android.content.Context;
32 import android.content.DialogInterface;
33 import android.content.Intent;
34 import android.content.Loader;
35 import android.content.pm.ApplicationInfo;
36 import android.content.pm.PackageInfo;
37 import android.content.pm.PackageManager;
38 import android.content.pm.PackageManager.NameNotFoundException;
39 import android.content.pm.ResolveInfo;
40 import android.content.pm.UserInfo;
41 import android.content.res.Resources;
42 import android.graphics.drawable.Drawable;
43 import android.icu.text.ListFormatter;
44 import android.net.INetworkStatsService;
45 import android.net.INetworkStatsSession;
46 import android.net.NetworkTemplate;
47 import android.net.TrafficStats;
48 import android.net.Uri;
49 import android.os.AsyncTask;
50 import android.os.BatteryStats;
51 import android.os.Bundle;
52 import android.os.RemoteException;
53 import android.os.ServiceManager;
54 import android.os.UserHandle;
55 import android.os.UserManager;
56 import android.support.annotation.VisibleForTesting;
57 import android.support.v7.preference.Preference;
58 import android.support.v7.preference.Preference.OnPreferenceClickListener;
59 import android.support.v7.preference.PreferenceCategory;
60 import android.support.v7.preference.PreferenceScreen;
61 import android.text.TextUtils;
62 import android.text.format.DateUtils;
63 import android.text.format.Formatter;
64 import android.util.Log;
65 import android.view.LayoutInflater;
66 import android.view.Menu;
67 import android.view.MenuInflater;
68 import android.view.MenuItem;
69 import android.view.View;
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;
76 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
77 import com.android.internal.os.BatterySipper;
78 import com.android.internal.os.BatteryStatsHelper;
79 import com.android.settings.AppHeader;
80 import com.android.settings.DeviceAdminAdd;
81 import com.android.settings.R;
82 import com.android.settings.SettingsActivity;
83 import com.android.settings.SettingsPreferenceFragment;
84 import com.android.settings.Utils;
85 import com.android.settings.applications.defaultapps.DefaultBrowserPreferenceController;
86 import com.android.settings.applications.defaultapps.DefaultEmergencyPreferenceController;
87 import com.android.settings.applications.defaultapps.DefaultHomePreferenceController;
88 import com.android.settings.applications.defaultapps.DefaultPhonePreferenceController;
89 import com.android.settings.applications.defaultapps.DefaultSmsPreferenceController;
90 import com.android.settings.applications.instantapps.InstantAppButtonsController;
91 import com.android.settings.datausage.AppDataUsage;
92 import com.android.settings.datausage.DataUsageList;
93 import com.android.settings.datausage.DataUsageSummary;
94 import com.android.settings.fuelgauge.AdvancedPowerUsageDetail;
95 import com.android.settings.fuelgauge.BatteryEntry;
96 import com.android.settings.fuelgauge.BatteryUtils;
97 import com.android.settings.notification.AppNotificationSettings;
98 import com.android.settings.notification.NotificationBackend;
99 import com.android.settings.notification.NotificationBackend.AppRow;
100 import com.android.settings.overlay.FeatureFactory;
101 import com.android.settingslib.AppItem;
102 import com.android.settingslib.RestrictedLockUtils;
103 import com.android.settingslib.applications.AppUtils;
104 import com.android.settingslib.applications.ApplicationsState;
105 import com.android.settingslib.applications.ApplicationsState.AppEntry;
106 import com.android.settingslib.applications.PermissionsSummaryHelper;
107 import com.android.settingslib.applications.PermissionsSummaryHelper.PermissionsResultCallback;
108 import com.android.settingslib.applications.StorageStatsSource;
109 import com.android.settingslib.applications.StorageStatsSource.AppStorageStats;
110 import com.android.settingslib.net.ChartData;
111 import com.android.settingslib.net.ChartDataLoader;
113 import java.lang.ref.WeakReference;
114 import java.util.ArrayList;
115 import java.util.HashSet;
116 import java.util.List;
117 import java.util.Set;
120 * Activity to display application information from Settings. This activity presents
121 * extended information associated with a package like code, data, total size, permissions
122 * used by the application and also the set of default launchable activities.
123 * For system applications, an option to clear user data is displayed only if data size is > 0.
124 * System applications that do not want clear user data do not have this option.
125 * For non-system applications, there is no option to clear data. Instead there is an option to
126 * uninstall the application.
128 public class InstalledAppDetails extends AppInfoBase
129 implements View.OnClickListener, OnPreferenceClickListener,
130 LoaderManager.LoaderCallbacks<AppStorageStats> {
132 private static final String LOG_TAG = "InstalledAppDetails";
135 public static final int UNINSTALL_ALL_USERS_MENU = 1;
136 public static final int UNINSTALL_UPDATES = 2;
138 // Result code identifiers
139 public static final int REQUEST_UNINSTALL = 0;
140 private static final int REQUEST_REMOVE_DEVICE_ADMIN = 1;
142 private static final int SUB_INFO_FRAGMENT = 1;
144 private static final int LOADER_CHART_DATA = 2;
145 private static final int LOADER_STORAGE = 3;
147 private static final int DLG_FORCE_STOP = DLG_BASE + 1;
148 private static final int DLG_DISABLE = DLG_BASE + 2;
149 private static final int DLG_SPECIAL_DISABLE = DLG_BASE + 3;
151 private static final String KEY_HEADER = "header_view";
152 private static final String KEY_INSTANT_APP_BUTTONS = "instant_app_buttons";
153 private static final String KEY_ACTION_BUTTONS = "action_buttons";
154 private static final String KEY_NOTIFICATION = "notification_settings";
155 private static final String KEY_STORAGE = "storage_settings";
156 private static final String KEY_PERMISSION = "permission_settings";
157 private static final String KEY_DATA = "data_settings";
158 private static final String KEY_LAUNCH = "preferred_settings";
159 private static final String KEY_BATTERY = "battery";
160 private static final String KEY_MEMORY = "memory";
161 private static final String KEY_VERSION = "app_version";
162 private static final String KEY_INSTANT_APP_SUPPORTED_LINKS =
163 "instant_app_launch_supported_domain_urls";
165 private final HashSet<String> mHomePackages = new HashSet<>();
167 private boolean mInitialized;
168 private boolean mShowUninstalled;
169 private LayoutPreference mHeader;
170 private LayoutPreference mActionButtons;
171 private Button mUninstallButton;
172 private boolean mUpdatedSysApp = false;
173 private Button mForceStopButton;
174 private Preference mNotificationPreference;
175 private Preference mStoragePreference;
176 private Preference mPermissionsPreference;
177 private Preference mLaunchPreference;
178 private Preference mDataPreference;
179 private Preference mMemoryPreference;
180 private Preference mVersionPreference;
181 private AppDomainsPreference mInstantAppDomainsPreference;
183 private boolean mDisableAfterUninstall;
185 // Used for updating notification preference.
186 private final NotificationBackend mBackend = new NotificationBackend();
188 private ChartData mChartData;
189 private INetworkStatsSession mStatsSession;
192 Preference mBatteryPreference;
194 BatterySipper mSipper;
196 BatteryStatsHelper mBatteryHelper;
198 protected ProcStatsData mStatsManager;
199 protected ProcStatsPackageEntry mStats;
201 private InstantAppButtonsController mInstantAppButtonsController;
203 private AppStorageStats mLastResult;
204 private String mBatteryPercent;
205 private BatteryUtils mBatteryUtils;
207 private boolean handleDisableable(Button button) {
208 boolean disableable = false;
209 // Try to prevent the user from bricking their phone
210 // by not allowing disabling of apps signed with the
211 // system cert and any launcher app in the system.
212 if (mHomePackages.contains(mAppEntry.info.packageName)
213 || Utils.isSystemPackage(getContext().getResources(), mPm, mPackageInfo)) {
214 // Disable button for core system applications.
215 button.setText(R.string.disable_text);
216 } else if (mAppEntry.info.enabled && !isDisabledUntilUsed()) {
217 button.setText(R.string.disable_text);
220 button.setText(R.string.enable_text);
227 private boolean isDisabledUntilUsed() {
228 return mAppEntry.info.enabledSetting
229 == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
232 private void initUninstallButtons() {
233 final boolean isBundled = (mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
234 boolean enabled = true;
236 enabled = handleDisableable(mUninstallButton);
238 enabled = initUnintsallButtonForUserApp();
240 // If this is a device admin, it can't be uninstalled or disabled.
241 // We do this here so the text of the button is still set correctly.
242 if (isBundled && mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
246 // We don't allow uninstalling DO/PO on *any* users, because if it's a system app,
247 // "uninstall" is actually "downgrade to the system version + disable", and "downgrade"
248 // will clear data on all users.
249 if (isProfileOrDeviceOwner(mPackageInfo.packageName)) {
253 // Don't allow uninstalling the device provisioning package.
254 if (Utils.isDeviceProvisioningPackage(getResources(), mAppEntry.info.packageName)) {
258 // If the uninstall intent is already queued, disable the uninstall button
259 if (mDpm.isUninstallInQueue(mPackageName)) {
263 // Home apps need special handling. Bundled ones we don't risk downgrading
264 // because that can interfere with home-key resolution. Furthermore, we
265 // can't allow uninstallation of the only home app, and we don't want to
266 // allow uninstallation of an explicitly preferred one -- the user can go
267 // to Home settings and pick a different one, after which we'll permit
268 // uninstallation of the now-not-default one.
269 if (enabled && mHomePackages.contains(mPackageInfo.packageName)) {
273 ArrayList<ResolveInfo> homeActivities = new ArrayList<ResolveInfo>();
274 ComponentName currentDefaultHome = mPm.getHomeActivities(homeActivities);
275 if (currentDefaultHome == null) {
276 // No preferred default, so permit uninstall only when
277 // there is more than one candidate
278 enabled = (mHomePackages.size() > 1);
280 // There is an explicit default home app -- forbid uninstall of
281 // that one, but permit it for installed-but-inactive ones.
282 enabled = !mPackageInfo.packageName.equals(currentDefaultHome.getPackageName());
287 if (mAppsControlDisallowedBySystem) {
292 IWebViewUpdateService webviewUpdateService =
293 IWebViewUpdateService.Stub.asInterface(ServiceManager.getService("webviewupdate"));
294 if (webviewUpdateService.isFallbackPackage(mAppEntry.info.packageName)) {
297 } catch (RemoteException e) {
298 throw new RuntimeException(e);
301 mUninstallButton.setEnabled(enabled);
304 mUninstallButton.setOnClickListener(this);
309 boolean initUnintsallButtonForUserApp() {
310 boolean enabled = true;
311 if ((mPackageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) == 0
312 && mUserManager.getUsers().size() >= 2) {
313 // When we have multiple users, there is a separate menu
314 // to uninstall for all users.
316 } else if (AppUtils.isInstant(mPackageInfo.applicationInfo)) {
318 mUninstallButton.setVisibility(View.GONE);
320 mUninstallButton.setText(R.string.uninstall_text);
324 /** Returns if the supplied package is device owner or profile owner of at least one user */
325 private boolean isProfileOrDeviceOwner(String packageName) {
326 List<UserInfo> userInfos = mUserManager.getUsers();
327 DevicePolicyManager dpm = (DevicePolicyManager)
328 getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
329 if (dpm.isDeviceOwnerAppOnAnyUser(packageName)) {
332 for (UserInfo userInfo : userInfos) {
333 ComponentName cn = dpm.getProfileOwnerAsUser(userInfo.id);
334 if (cn != null && cn.getPackageName().equals(packageName)) {
341 /** Called when the activity is first created. */
343 public void onCreate(Bundle icicle) {
344 super.onCreate(icicle);
345 final Activity activity = getActivity();
347 if (!ensurePackageInfoAvailable(activity)) {
351 setHasOptionsMenu(true);
352 addPreferencesFromResource(R.xml.installed_app_details_ia);
354 if (Utils.isBandwidthControlEnabled()) {
355 INetworkStatsService statsService = INetworkStatsService.Stub.asInterface(
356 ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
358 mStatsSession = statsService.openSession();
359 } catch (RemoteException e) {
360 throw new RuntimeException(e);
363 removePreference(KEY_DATA);
365 mBatteryHelper = new BatteryStatsHelper(getActivity(), true);
366 mBatteryUtils = BatteryUtils.getInstance(getContext());
370 public int getMetricsCategory() {
371 return MetricsEvent.APPLICATIONS_INSTALLED_APP_DETAILS;
375 public void onResume() {
380 AppItem app = new AppItem(mAppEntry.info.uid);
381 app.addUid(mAppEntry.info.uid);
382 if (mStatsSession != null) {
383 LoaderManager loaderManager = getLoaderManager();
384 loaderManager.restartLoader(LOADER_CHART_DATA,
385 ChartDataLoader.buildArgs(getTemplate(getContext()), app),
387 loaderManager.restartLoader(LOADER_STORAGE, Bundle.EMPTY, this);
389 new BatteryUpdater().execute();
390 new MemoryUpdater().execute();
391 updateDynamicPrefs();
395 public void onPause() {
396 getLoaderManager().destroyLoader(LOADER_CHART_DATA);
401 public void onDestroy() {
402 TrafficStats.closeQuietly(mStatsSession);
406 public void onActivityCreated(Bundle savedInstanceState) {
407 super.onActivityCreated(savedInstanceState);
411 final Activity activity = getActivity();
412 mHeader = (LayoutPreference) findPreference(KEY_HEADER);
413 mActionButtons = (LayoutPreference) findPreference(KEY_ACTION_BUTTONS);
414 FeatureFactory.getFactory(activity)
415 .getApplicationFeatureProvider(activity)
416 .newAppHeaderController(this, mHeader.findViewById(R.id.app_snippet))
417 .setPackageName(mPackageName)
418 .setButtonActions(AppHeaderController.ActionType.ACTION_APP_PREFERENCE,
419 AppHeaderController.ActionType.ACTION_NONE)
420 .styleActionBar(activity)
421 .bindAppHeaderButtons();
422 prepareUninstallAndStop();
424 mNotificationPreference = findPreference(KEY_NOTIFICATION);
425 mNotificationPreference.setOnPreferenceClickListener(this);
426 mStoragePreference = findPreference(KEY_STORAGE);
427 mStoragePreference.setOnPreferenceClickListener(this);
428 mPermissionsPreference = findPreference(KEY_PERMISSION);
429 mPermissionsPreference.setOnPreferenceClickListener(this);
430 mDataPreference = findPreference(KEY_DATA);
431 if (mDataPreference != null) {
432 mDataPreference.setOnPreferenceClickListener(this);
434 mBatteryPreference = findPreference(KEY_BATTERY);
435 mBatteryPreference.setEnabled(false);
436 mBatteryPreference.setOnPreferenceClickListener(this);
437 mMemoryPreference = findPreference(KEY_MEMORY);
438 mMemoryPreference.setOnPreferenceClickListener(this);
439 mVersionPreference = findPreference(KEY_VERSION);
440 mInstantAppDomainsPreference =
441 (AppDomainsPreference) findPreference(KEY_INSTANT_APP_SUPPORTED_LINKS);
442 mLaunchPreference = findPreference(KEY_LAUNCH);
443 if (mAppEntry != null && mAppEntry.info != null) {
444 if ((mAppEntry.info.flags&ApplicationInfo.FLAG_INSTALLED) == 0 ||
445 !mAppEntry.info.enabled) {
446 mLaunchPreference.setEnabled(false);
448 mLaunchPreference.setOnPreferenceClickListener(this);
451 mLaunchPreference.setEnabled(false);
456 public void onPackageSizeChanged(String packageName) {
461 * Ensures the {@link PackageInfo} is available to proceed. If it's not available, the fragment
464 * @return true if packageInfo is available.
466 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
467 boolean ensurePackageInfoAvailable(Activity activity) {
468 if (mPackageInfo == null) {
470 Log.w(LOG_TAG, "Package info not available. Is this package already uninstalled?");
471 activity.finishAndRemoveTask();
477 private void prepareUninstallAndStop() {
478 mForceStopButton = (Button) mActionButtons.findViewById(R.id.right_button);
479 mForceStopButton.setText(R.string.force_stop);
480 mUninstallButton = (Button) mActionButtons.findViewById(R.id.left_button);
481 mForceStopButton.setEnabled(false);
485 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
486 menu.add(0, UNINSTALL_UPDATES, 0, R.string.app_factory_reset)
487 .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
488 menu.add(0, UNINSTALL_ALL_USERS_MENU, 1, R.string.uninstall_all_users_text)
489 .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
493 public void onPrepareOptionsMenu(Menu menu) {
497 menu.findItem(UNINSTALL_ALL_USERS_MENU).setVisible(shouldShowUninstallForAll(mAppEntry));
498 mUpdatedSysApp = (mAppEntry.info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
499 MenuItem uninstallUpdatesItem = menu.findItem(UNINSTALL_UPDATES);
500 uninstallUpdatesItem.setVisible(mUpdatedSysApp && !mAppsControlDisallowedBySystem);
501 if (uninstallUpdatesItem.isVisible()) {
502 RestrictedLockUtils.setMenuItemAsDisabledByAdmin(getActivity(),
503 uninstallUpdatesItem, mAppsControlDisallowedAdmin);
508 public boolean onOptionsItemSelected(MenuItem item) {
509 switch (item.getItemId()) {
510 case UNINSTALL_ALL_USERS_MENU:
511 uninstallPkg(mAppEntry.info.packageName, true, false);
513 case UNINSTALL_UPDATES:
514 uninstallPkg(mAppEntry.info.packageName, false, false);
521 public void onActivityResult(int requestCode, int resultCode, Intent data) {
522 super.onActivityResult(requestCode, resultCode, data);
523 switch (requestCode) {
524 case REQUEST_UNINSTALL:
525 if (mDisableAfterUninstall) {
526 mDisableAfterUninstall = false;
527 new DisableChanger(this, mAppEntry.info,
528 PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER)
529 .execute((Object)null);
531 // continue with following operations
532 case REQUEST_REMOVE_DEVICE_ADMIN:
534 setIntentAndFinish(true, true);
536 startListeningToPackageRemove();
543 public Loader<AppStorageStats> onCreateLoader(int id, Bundle args) {
544 Context context = getContext();
545 return new FetchPackageStorageAsyncLoader(
546 context, new StorageStatsSource(context), mAppEntry.info, UserHandle.of(mUserId));
550 public void onLoadFinished(Loader<AppStorageStats> loader, AppStorageStats result) {
551 mLastResult = result;
556 public void onLoaderReset(Loader<AppStorageStats> loader) {
560 * Utility method to hide and show specific preferences based on whether the app being displayed
561 * is an Instant App or an installed app.
564 void prepareInstantAppPrefs() {
565 final boolean isInstant = AppUtils.isInstant(mPackageInfo.applicationInfo);
567 Set<String> handledDomainSet = Utils.getHandledDomains(mPm, mPackageInfo.packageName);
568 String[] handledDomains = handledDomainSet.toArray(new String[handledDomainSet.size()]);
569 mInstantAppDomainsPreference.setTitles(handledDomains);
570 // Dummy values, unused in the implementation
571 mInstantAppDomainsPreference.setValues(new int[handledDomains.length]);
572 getPreferenceScreen().removePreference(mLaunchPreference);
574 getPreferenceScreen().removePreference(mInstantAppDomainsPreference);
578 // Utility method to set application label and icon.
579 private void setAppLabelAndIcon(PackageInfo pkgInfo) {
580 final View appSnippet = mHeader.findViewById(R.id.app_snippet);
581 mState.ensureIcon(mAppEntry);
582 final Activity activity = getActivity();
583 final boolean isInstantApp = AppUtils.isInstant(mPackageInfo.applicationInfo);
584 final CharSequence summary =
585 isInstantApp ? null : getString(Utils.getInstallationStatus(mAppEntry.info));
586 FeatureFactory.getFactory(activity)
587 .getApplicationFeatureProvider(activity)
588 .newAppHeaderController(this, appSnippet)
592 .setIsInstantApp(isInstantApp)
593 .done(activity, false /* rebindActions */);
594 mVersionPreference.setSummary(getString(R.string.version_text, pkgInfo.versionName));
598 boolean shouldShowUninstallForAll(ApplicationsState.AppEntry appEntry) {
599 boolean showIt = true;
600 if (mUpdatedSysApp) {
602 } else if (appEntry == null) {
604 } else if ((appEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
606 } else if (mPackageInfo == null || mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
608 } else if (UserHandle.myUserId() != 0) {
610 } else if (mUserManager.getUsers().size() < 2) {
612 } else if (PackageUtil.countPackageInUsers(mPm, mUserManager, mPackageName) < 2
613 && (appEntry.info.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
615 } else if (AppUtils.isInstant(appEntry.info)) {
621 private boolean signaturesMatch(String pkg1, String pkg2) {
622 if (pkg1 != null && pkg2 != null) {
624 final int match = mPm.checkSignatures(pkg1, pkg2);
625 if (match >= PackageManager.SIGNATURE_MATCH) {
628 } catch (Exception e) {
629 // e.g. named alternate package not found during lookup;
630 // this is an expected case sometimes
637 protected boolean refreshUi() {
639 if (mAppEntry == null) {
640 return false; // onCreate must have failed, make sure to exit
643 if (mPackageInfo == null) {
644 return false; // onCreate must have failed, make sure to exit
647 // Get list of "home" apps and trace through any meta-data references
648 List<ResolveInfo> homeActivities = new ArrayList<ResolveInfo>();
649 mPm.getHomeActivities(homeActivities);
650 mHomePackages.clear();
651 for (int i = 0; i< homeActivities.size(); i++) {
652 ResolveInfo ri = homeActivities.get(i);
653 final String activityPkg = ri.activityInfo.packageName;
654 mHomePackages.add(activityPkg);
656 // Also make sure to include anything proxying for the home app
657 final Bundle metadata = ri.activityInfo.metaData;
658 if (metadata != null) {
659 final String metaPkg = metadata.getString(ActivityManager.META_HOME_ALTERNATE);
660 if (signaturesMatch(metaPkg, activityPkg)) {
661 mHomePackages.add(metaPkg);
667 setAppLabelAndIcon(mPackageInfo);
668 initUninstallButtons();
669 prepareInstantAppPrefs();
671 // Update the preference summaries.
672 Activity context = getActivity();
673 boolean isExternal = ((mAppEntry.info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
674 mStoragePreference.setSummary(getStorageSummary(context, mLastResult, isExternal));
676 PermissionsSummaryHelper.getPermissionSummary(getContext(),
677 mPackageName, mPermissionCallback);
678 mLaunchPreference.setSummary(AppUtils.getLaunchByDefaultSummary(mAppEntry, mUsbManager,
680 mNotificationPreference.setSummary(getNotificationSummary(mAppEntry, context,
682 if (mDataPreference != null) {
683 mDataPreference.setSummary(getDataSummary());
689 // First time init: are we displaying an uninstalled app?
691 mShowUninstalled = (mAppEntry.info.flags&ApplicationInfo.FLAG_INSTALLED) == 0;
693 // All other times: if the app no longer exists then we want
696 ApplicationInfo ainfo = context.getPackageManager().getApplicationInfo(
697 mAppEntry.info.packageName,
698 PackageManager.MATCH_DISABLED_COMPONENTS
699 | PackageManager.MATCH_ANY_USER);
700 if (!mShowUninstalled) {
701 // If we did not start out with the app uninstalled, then
702 // it transitioning to the uninstalled state for the current
703 // user means we should go away as well.
704 return (ainfo.flags&ApplicationInfo.FLAG_INSTALLED) != 0;
706 } catch (NameNotFoundException e) {
714 private void updateBattery() {
715 if (mSipper != null) {
716 mBatteryPreference.setEnabled(true);
717 final int dischargeAmount = mBatteryHelper.getStats().getDischargeAmount(
718 BatteryStats.STATS_SINCE_CHARGED);
720 final List<BatterySipper> usageList = new ArrayList<>(mBatteryHelper.getUsageList());
721 final double hiddenAmount = mBatteryUtils.removeHiddenBatterySippers(usageList);
722 final int percentOfMax = (int) mBatteryUtils.calculateBatteryPercent(
723 mSipper.totalPowerMah, mBatteryHelper.getTotalPower(), hiddenAmount,
725 mBatteryPercent = Utils.formatPercentage(percentOfMax);
726 mBatteryPreference.setSummary(getString(R.string.battery_summary, mBatteryPercent));
728 mBatteryPreference.setEnabled(false);
729 mBatteryPreference.setSummary(getString(R.string.no_battery_summary));
733 private CharSequence getDataSummary() {
734 if (mChartData != null) {
735 long totalBytes = mChartData.detail.getTotalBytes();
736 if (totalBytes == 0) {
737 return getString(R.string.no_data_usage);
739 Context context = getActivity();
740 return getString(R.string.data_summary_format,
741 Formatter.formatFileSize(context, totalBytes),
742 DateUtils.formatDateTime(context, mChartData.detail.getStart(),
743 DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH));
745 return getString(R.string.computing_size);
749 static CharSequence getStorageSummary(
750 Context context, AppStorageStats stats, boolean isExternal) {
752 return context.getText(R.string.computing_size);
754 CharSequence storageType = context.getString(isExternal
755 ? R.string.storage_type_external
756 : R.string.storage_type_internal);
757 return context.getString(R.string.storage_summary_format,
758 getSize(context, stats), storageType.toString().toLowerCase());
762 private static CharSequence getSize(Context context, AppStorageStats stats) {
763 return Formatter.formatFileSize(context, stats.getTotalBytes());
768 protected AlertDialog createDialog(int id, int errorCode) {
771 return new AlertDialog.Builder(getActivity())
772 .setMessage(getActivity().getText(R.string.app_disable_dlg_text))
773 .setPositiveButton(R.string.app_disable_dlg_positive,
774 new DialogInterface.OnClickListener() {
775 public void onClick(DialogInterface dialog, int which) {
777 mMetricsFeatureProvider.action(getContext(),
778 MetricsEvent.ACTION_SETTINGS_DISABLE_APP);
779 new DisableChanger(InstalledAppDetails.this, mAppEntry.info,
780 PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER)
781 .execute((Object)null);
784 .setNegativeButton(R.string.dlg_cancel, null)
786 case DLG_SPECIAL_DISABLE:
787 return new AlertDialog.Builder(getActivity())
788 .setMessage(getActivity().getText(R.string.app_disable_dlg_text))
789 .setPositiveButton(R.string.app_disable_dlg_positive,
790 new DialogInterface.OnClickListener() {
791 public void onClick(DialogInterface dialog, int which) {
792 // Disable the app and ask for uninstall
793 mMetricsFeatureProvider.action(getContext(),
794 MetricsEvent.ACTION_SETTINGS_DISABLE_APP);
795 uninstallPkg(mAppEntry.info.packageName,
799 .setNegativeButton(R.string.dlg_cancel, null)
802 return new AlertDialog.Builder(getActivity())
803 .setTitle(getActivity().getText(R.string.force_stop_dlg_title))
804 .setMessage(getActivity().getText(R.string.force_stop_dlg_text))
805 .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
806 public void onClick(DialogInterface dialog, int which) {
808 forceStopPackage(mAppEntry.info.packageName);
811 .setNegativeButton(R.string.dlg_cancel, null)
814 if (mInstantAppButtonsController != null) {
815 return mInstantAppButtonsController.createDialog(id);
820 private void uninstallPkg(String packageName, boolean allUsers, boolean andDisable) {
821 stopListeningToPackageRemove();
822 // Create new intent to launch Uninstaller activity
823 Uri packageURI = Uri.parse("package:"+packageName);
824 Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageURI);
825 uninstallIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, allUsers);
826 mMetricsFeatureProvider.action(
827 getContext(), MetricsEvent.ACTION_SETTINGS_UNINSTALL_APP);
828 startActivityForResult(uninstallIntent, REQUEST_UNINSTALL);
829 mDisableAfterUninstall = andDisable;
832 private void forceStopPackage(String pkgName) {
833 mMetricsFeatureProvider.action(getContext(), MetricsEvent.ACTION_APP_FORCE_STOP, pkgName);
834 ActivityManager am = (ActivityManager) getActivity().getSystemService(
835 Context.ACTIVITY_SERVICE);
836 Log.d(LOG_TAG, "Stopping package " + pkgName);
837 am.forceStopPackage(pkgName);
838 int userId = UserHandle.getUserId(mAppEntry.info.uid);
839 mState.invalidatePackage(pkgName, userId);
840 ApplicationsState.AppEntry newEnt = mState.getEntry(pkgName, userId);
841 if (newEnt != null) {
847 private void updateForceStopButton(boolean enabled) {
848 if (mAppsControlDisallowedBySystem) {
849 mForceStopButton.setEnabled(false);
851 mForceStopButton.setEnabled(enabled);
852 mForceStopButton.setOnClickListener(this);
857 void checkForceStop() {
858 if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
859 // User can't force stop device admin.
860 Log.w(LOG_TAG, "User can't force stop device admin");
861 updateForceStopButton(false);
862 } else if (AppUtils.isInstant(mPackageInfo.applicationInfo)) {
863 updateForceStopButton(false);
864 mForceStopButton.setVisibility(View.GONE);
865 } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_STOPPED) == 0) {
866 // If the app isn't explicitly stopped, then always show the
867 // force stop button.
868 Log.w(LOG_TAG, "App is not explicitly stopped");
869 updateForceStopButton(true);
871 Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART,
872 Uri.fromParts("package", mAppEntry.info.packageName, null));
873 intent.putExtra(Intent.EXTRA_PACKAGES, new String[] { mAppEntry.info.packageName });
874 intent.putExtra(Intent.EXTRA_UID, mAppEntry.info.uid);
875 intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(mAppEntry.info.uid));
876 Log.d(LOG_TAG, "Sending broadcast to query restart status for "
877 + mAppEntry.info.packageName);
878 getActivity().sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
879 mCheckKillProcessesReceiver, null, Activity.RESULT_CANCELED, null, null);
883 private void startManagePermissionsActivity() {
884 // start new activity to manage app permissions
885 Intent intent = new Intent(Intent.ACTION_MANAGE_APP_PERMISSIONS);
886 intent.putExtra(Intent.EXTRA_PACKAGE_NAME, mAppEntry.info.packageName);
887 intent.putExtra(AppHeader.EXTRA_HIDE_INFO_BUTTON, true);
889 getActivity().startActivityForResult(intent, SUB_INFO_FRAGMENT);
890 } catch (ActivityNotFoundException e) {
891 Log.w(LOG_TAG, "No app can handle android.intent.action.MANAGE_APP_PERMISSIONS");
895 private void startAppInfoFragment(Class<?> fragment, CharSequence title) {
896 startAppInfoFragment(fragment, title, this, mAppEntry);
899 public static void startAppInfoFragment(Class<?> fragment, CharSequence title,
900 SettingsPreferenceFragment caller, AppEntry appEntry) {
901 // start new fragment to display extended information
902 Bundle args = new Bundle();
903 args.putString(ARG_PACKAGE_NAME, appEntry.info.packageName);
904 args.putInt(ARG_PACKAGE_UID, appEntry.info.uid);
905 args.putBoolean(AppHeader.EXTRA_HIDE_INFO_BUTTON, true);
907 SettingsActivity sa = (SettingsActivity) caller.getActivity();
908 sa.startPreferencePanel(caller, fragment.getName(), args, -1, title, caller,
913 * Method implementing functionality of buttons clicked
914 * @see android.view.View.OnClickListener#onClick(android.view.View)
916 public void onClick(View v) {
917 if (mAppEntry == null) {
918 setIntentAndFinish(true, true);
921 String packageName = mAppEntry.info.packageName;
922 if (v == mUninstallButton) {
923 if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
924 stopListeningToPackageRemove();
925 Activity activity = getActivity();
926 Intent uninstallDAIntent = new Intent(activity, DeviceAdminAdd.class);
927 uninstallDAIntent.putExtra(DeviceAdminAdd.EXTRA_DEVICE_ADMIN_PACKAGE_NAME,
929 mMetricsFeatureProvider.action(
930 activity, MetricsEvent.ACTION_SETTINGS_UNINSTALL_DEVICE_ADMIN);
931 activity.startActivityForResult(uninstallDAIntent, REQUEST_REMOVE_DEVICE_ADMIN);
934 EnforcedAdmin admin = RestrictedLockUtils.checkIfUninstallBlocked(getActivity(),
935 packageName, mUserId);
936 boolean uninstallBlockedBySystem = mAppsControlDisallowedBySystem ||
937 RestrictedLockUtils.hasBaseUserRestriction(getActivity(), packageName, mUserId);
938 if (admin != null && !uninstallBlockedBySystem) {
939 RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getActivity(), admin);
940 } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
941 if (mAppEntry.info.enabled && !isDisabledUntilUsed()) {
942 // If the system app has an update and this is the only user on the device,
943 // then offer to downgrade the app, otherwise only offer to disable the
944 // app for this user.
945 if (mUpdatedSysApp && isSingleUser()) {
946 showDialogInner(DLG_SPECIAL_DISABLE, 0);
948 showDialogInner(DLG_DISABLE, 0);
951 mMetricsFeatureProvider.action(
953 mAppEntry.info.enabled
954 ? MetricsEvent.ACTION_SETTINGS_DISABLE_APP
955 : MetricsEvent.ACTION_SETTINGS_ENABLE_APP);
956 new DisableChanger(this, mAppEntry.info,
957 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT)
958 .execute((Object) null);
960 } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_INSTALLED) == 0) {
961 uninstallPkg(packageName, true, false);
963 uninstallPkg(packageName, false, false);
965 } else if (v == mForceStopButton) {
966 if (mAppsControlDisallowedAdmin != null && !mAppsControlDisallowedBySystem) {
967 RestrictedLockUtils.sendShowAdminSupportDetailsIntent(
968 getActivity(), mAppsControlDisallowedAdmin);
970 showDialogInner(DLG_FORCE_STOP, 0);
971 //forceStopPackage(mAppInfo.packageName);
976 /** Returns whether there is only one user on this device, not including the system-only user */
977 private boolean isSingleUser() {
978 final int userCount = mUserManager.getUserCount();
979 return userCount == 1
980 || (mUserManager.isSplitSystemUser() && userCount == 2);
984 public boolean onPreferenceClick(Preference preference) {
985 if (preference == mStoragePreference) {
986 startAppInfoFragment(AppStorageSettings.class, mStoragePreference.getTitle());
987 } else if (preference == mNotificationPreference) {
988 startAppInfoFragment(AppNotificationSettings.class,
989 getString(R.string.app_notifications_title));
990 } else if (preference == mPermissionsPreference) {
991 startManagePermissionsActivity();
992 } else if (preference == mLaunchPreference) {
993 startAppInfoFragment(AppLaunchSettings.class, mLaunchPreference.getTitle());
994 } else if (preference == mMemoryPreference) {
995 ProcessStatsBase.launchMemoryDetail((SettingsActivity) getActivity(),
996 mStatsManager.getMemInfo(), mStats, false);
997 } else if (preference == mDataPreference) {
998 startAppInfoFragment(AppDataUsage.class, getString(R.string.app_data_usage));
999 } else if (preference == mBatteryPreference) {
1000 BatteryEntry entry = new BatteryEntry(getContext(), null, mUserManager, mSipper);
1001 AdvancedPowerUsageDetail.startBatteryDetailPage((SettingsActivity) getActivity(), this,
1002 mBatteryHelper, BatteryStats.STATS_SINCE_CHARGED, entry, mBatteryPercent);
1009 private void addDynamicPrefs() {
1010 if (UserManager.get(getContext()).isManagedProfile()) {
1013 final PreferenceScreen screen = getPreferenceScreen();
1014 final Context context = getContext();
1015 if (DefaultHomePreferenceController.hasHomePreference(mPackageName, context)) {
1016 screen.addPreference(new ShortcutPreference(getPrefContext(),
1017 AdvancedAppSettings.class, "default_home", R.string.home_app,
1018 R.string.configure_apps));
1020 if (DefaultBrowserPreferenceController.hasBrowserPreference(mPackageName, context)) {
1021 screen.addPreference(new ShortcutPreference(getPrefContext(),
1022 AdvancedAppSettings.class, "default_browser", R.string.default_browser_title,
1023 R.string.configure_apps));
1025 if (DefaultPhonePreferenceController.hasPhonePreference(mPackageName, context)) {
1026 screen.addPreference(new ShortcutPreference(getPrefContext(),
1027 AdvancedAppSettings.class, "default_phone_app", R.string.default_phone_title,
1028 R.string.configure_apps));
1030 if (DefaultEmergencyPreferenceController.hasEmergencyPreference(mPackageName, context)) {
1031 screen.addPreference(new ShortcutPreference(getPrefContext(),
1032 AdvancedAppSettings.class, "default_emergency_app",
1033 R.string.default_emergency_app, R.string.configure_apps));
1035 if (DefaultSmsPreferenceController.hasSmsPreference(mPackageName, context)) {
1036 screen.addPreference(new ShortcutPreference(getPrefContext(),
1037 AdvancedAppSettings.class, "default_sms_app", R.string.sms_application_title,
1038 R.string.configure_apps));
1041 // Get the package info with the activities
1042 PackageInfo packageInfoWithActivities = null;
1044 packageInfoWithActivities = mPm.getPackageInfoAsUser(mPackageName,
1045 PackageManager.GET_ACTIVITIES, UserHandle.myUserId());
1046 } catch (NameNotFoundException e) {
1047 Log.e(TAG, "Exception while retrieving the package info of " + mPackageName, e);
1050 boolean hasDrawOverOtherApps = hasPermission(permission.SYSTEM_ALERT_WINDOW);
1051 boolean hasWriteSettings = hasPermission(permission.WRITE_SETTINGS);
1052 boolean hasPictureInPictureActivities = (packageInfoWithActivities != null) &&
1053 PictureInPictureSettings.checkPackageHasPictureInPictureActivities(
1054 packageInfoWithActivities.packageName,
1055 packageInfoWithActivities.activities);
1056 boolean isPotentialAppSource = isPotentialAppSource();
1057 if (hasDrawOverOtherApps || hasWriteSettings || hasPictureInPictureActivities ||
1058 isPotentialAppSource) {
1059 PreferenceCategory category = new PreferenceCategory(getPrefContext());
1060 category.setTitle(R.string.advanced_apps);
1061 screen.addPreference(category);
1063 if (hasDrawOverOtherApps) {
1064 Preference pref = new Preference(getPrefContext());
1065 pref.setTitle(R.string.draw_overlay);
1066 pref.setKey("system_alert_window");
1067 pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
1069 public boolean onPreferenceClick(Preference preference) {
1070 startAppInfoFragment(DrawOverlayDetails.class,
1071 getString(R.string.draw_overlay));
1075 category.addPreference(pref);
1077 if (hasWriteSettings) {
1078 Preference pref = new Preference(getPrefContext());
1079 pref.setTitle(R.string.write_settings);
1080 pref.setKey("write_settings_apps");
1081 pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
1083 public boolean onPreferenceClick(Preference preference) {
1084 startAppInfoFragment(WriteSettingsDetails.class,
1085 getString(R.string.write_settings));
1089 category.addPreference(pref);
1091 if (hasPictureInPictureActivities) {
1092 Preference pref = new Preference(getPrefContext());
1093 pref.setTitle(R.string.picture_in_picture_app_detail_title);
1094 pref.setKey("picture_in_picture");
1095 pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
1097 public boolean onPreferenceClick(Preference preference) {
1098 AppInfoBase.startAppInfoFragment(PictureInPictureDetails.class,
1099 R.string.picture_in_picture_app_detail_title, mPackageName,
1100 mPackageInfo.applicationInfo.uid, InstalledAppDetails.this,
1101 -1, getMetricsCategory());
1105 category.addPreference(pref);
1107 if (isPotentialAppSource) {
1108 Preference pref = new Preference(getPrefContext());
1109 pref.setTitle(R.string.install_other_apps);
1110 pref.setKey("install_other_apps");
1111 pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
1113 public boolean onPreferenceClick(Preference preference) {
1114 startAppInfoFragment(ExternalSourcesDetails.class,
1115 getString(R.string.install_other_apps));
1119 category.addPreference(pref);
1123 addAppInstallerInfoPref(screen);
1124 maybeAddInstantAppButtons();
1127 private boolean isPotentialAppSource() {
1128 AppStateInstallAppsBridge.InstallAppsState appState =
1129 new AppStateInstallAppsBridge(getContext(), null, null)
1130 .createInstallAppsStateFor(mPackageName, mPackageInfo.applicationInfo.uid);
1131 return appState.isPotentialAppSource();
1134 private void addAppInstallerInfoPref(PreferenceScreen screen) {
1135 String installerPackageName =
1136 AppStoreUtil.getInstallerPackageName(getContext(), mPackageName);
1138 final CharSequence installerLabel = Utils.getApplicationLabel(getContext(),
1139 installerPackageName);
1140 if (installerLabel == null) {
1143 final int detailsStringId = AppUtils.isInstant(mPackageInfo.applicationInfo)
1144 ? R.string.instant_app_details_summary
1145 : R.string.app_install_details_summary;
1146 PreferenceCategory category = new PreferenceCategory(getPrefContext());
1147 category.setTitle(R.string.app_install_details_group_title);
1148 screen.addPreference(category);
1149 Preference pref = new Preference(getPrefContext());
1150 pref.setTitle(R.string.app_install_details_title);
1151 pref.setKey("app_info_store");
1152 pref.setSummary(getString(detailsStringId, installerLabel));
1155 AppStoreUtil.getAppStoreLink(getContext(), installerPackageName, mPackageName);
1156 if (intent != null) {
1157 pref.setIntent(intent);
1159 pref.setEnabled(false);
1161 category.addPreference(pref);
1165 void maybeAddInstantAppButtons() {
1166 if (AppUtils.isInstant(mPackageInfo.applicationInfo)) {
1167 LayoutPreference buttons = (LayoutPreference) findPreference(KEY_INSTANT_APP_BUTTONS);
1168 final Activity activity = getActivity();
1169 mInstantAppButtonsController = FeatureFactory.getFactory(activity)
1170 .getApplicationFeatureProvider(activity)
1171 .newInstantAppButtonsController(this,
1172 buttons.findViewById(R.id.instant_app_button_container),
1173 id -> showDialogInner(id, 0))
1174 .setPackageName(mPackageName)
1179 private boolean hasPermission(String permission) {
1180 if (mPackageInfo == null || mPackageInfo.requestedPermissions == null) {
1183 for (int i = 0; i < mPackageInfo.requestedPermissions.length; i++) {
1184 if (mPackageInfo.requestedPermissions[i].equals(permission)) {
1191 private void updateDynamicPrefs() {
1192 final Context context = getContext();
1193 Preference pref = findPreference("default_home");
1196 pref.setSummary(DefaultHomePreferenceController.isHomeDefault(mPackageName, context)
1197 ? R.string.yes : R.string.no);
1199 pref = findPreference("default_browser");
1201 pref.setSummary(new DefaultBrowserPreferenceController(context)
1202 .isBrowserDefault(mPackageName, mUserId)
1203 ? R.string.yes : R.string.no);
1205 pref = findPreference("default_phone_app");
1208 DefaultPhonePreferenceController.isPhoneDefault(mPackageName, context)
1209 ? R.string.yes : R.string.no);
1211 pref = findPreference("default_emergency_app");
1213 pref.setSummary(DefaultEmergencyPreferenceController.isEmergencyDefault(mPackageName,
1214 getContext()) ? R.string.yes : R.string.no);
1216 pref = findPreference("default_sms_app");
1218 pref.setSummary(DefaultSmsPreferenceController.isSmsDefault(mPackageName, context)
1219 ? R.string.yes : R.string.no);
1221 pref = findPreference("system_alert_window");
1223 pref.setSummary(DrawOverlayDetails.getSummary(getContext(), mAppEntry));
1225 pref = findPreference("picture_in_picture");
1227 pref.setSummary(PictureInPictureDetails.getPreferenceSummary(getContext(),
1228 mPackageInfo.applicationInfo.uid, mPackageName));
1230 pref = findPreference("write_settings_apps");
1232 pref.setSummary(WriteSettingsDetails.getSummary(getContext(), mAppEntry));
1234 pref = findPreference("install_other_apps");
1236 pref.setSummary(ExternalSourcesDetails.getPreferenceSummary(getContext(), mAppEntry));
1241 * @deprecated app info pages should use {@link AppHeaderController} to show the app header.
1243 public static void setupAppSnippet(View appSnippet, CharSequence label, Drawable icon,
1244 CharSequence versionName) {
1245 LayoutInflater.from(appSnippet.getContext()).inflate(R.layout.widget_text_views,
1246 (ViewGroup) appSnippet.findViewById(android.R.id.widget_frame));
1248 ImageView iconView = (ImageView) appSnippet.findViewById(R.id.app_detail_icon);
1249 iconView.setImageDrawable(icon);
1250 // Set application name.
1251 TextView labelView = (TextView) appSnippet.findViewById(R.id.app_detail_title);
1252 labelView.setText(label);
1253 // Version number of application
1254 TextView appVersion = (TextView) appSnippet.findViewById(R.id.widget_text1);
1256 if (!TextUtils.isEmpty(versionName)) {
1257 appVersion.setSelected(true);
1258 appVersion.setVisibility(View.VISIBLE);
1259 appVersion.setText(appSnippet.getContext().getString(R.string.version_text,
1260 String.valueOf(versionName)));
1262 appVersion.setVisibility(View.INVISIBLE);
1266 public static NetworkTemplate getTemplate(Context context) {
1267 if (DataUsageList.hasReadyMobileRadio(context)) {
1268 return NetworkTemplate.buildTemplateMobileWildcard();
1270 if (DataUsageSummary.hasWifiRadio(context)) {
1271 return NetworkTemplate.buildTemplateWifiWildcard();
1273 return NetworkTemplate.buildTemplateEthernet();
1276 public static CharSequence getNotificationSummary(AppEntry appEntry, Context context,
1277 NotificationBackend backend) {
1278 AppRow appRow = backend.loadAppRow(context, context.getPackageManager(), appEntry.info);
1279 return getNotificationSummary(appRow, context);
1282 public static CharSequence getNotificationSummary(AppRow appRow, Context context) {
1283 // TODO: implement summary when it is known what it should say
1288 protected void onPackageRemoved() {
1289 getActivity().finishActivity(SUB_INFO_FRAGMENT);
1290 super.onPackageRemoved();
1293 private class MemoryUpdater extends AsyncTask<Void, Void, ProcStatsPackageEntry> {
1296 protected ProcStatsPackageEntry doInBackground(Void... params) {
1297 if (getActivity() == null) {
1300 if (mPackageInfo == null) {
1303 if (mStatsManager == null) {
1304 mStatsManager = new ProcStatsData(getActivity(), false);
1305 mStatsManager.setDuration(ProcessStatsBase.sDurations[0]);
1307 mStatsManager.refreshStats(true);
1308 for (ProcStatsPackageEntry pkgEntry : mStatsManager.getEntries()) {
1309 for (ProcStatsEntry entry : pkgEntry.mEntries) {
1310 if (entry.mUid == mPackageInfo.applicationInfo.uid) {
1311 pkgEntry.updateMetrics();
1320 protected void onPostExecute(ProcStatsPackageEntry entry) {
1321 if (getActivity() == null) {
1324 if (entry != null) {
1326 mMemoryPreference.setEnabled(true);
1327 double amount = Math.max(entry.mRunWeight, entry.mBgWeight)
1328 * mStatsManager.getMemInfo().weightToRam;
1329 mMemoryPreference.setSummary(getString(R.string.memory_use_summary,
1330 Formatter.formatShortFileSize(getContext(), (long) amount)));
1332 mMemoryPreference.setEnabled(false);
1333 mMemoryPreference.setSummary(getString(R.string.no_memory_use_summary));
1339 private class BatteryUpdater extends AsyncTask<Void, Void, Void> {
1341 protected Void doInBackground(Void... params) {
1342 mBatteryHelper.create((Bundle) null);
1343 mBatteryHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED,
1344 mUserManager.getUserProfiles());
1345 List<BatterySipper> usageList = mBatteryHelper.getUsageList();
1346 final int N = usageList.size();
1347 for (int i = 0; i < N; i++) {
1348 BatterySipper sipper = usageList.get(i);
1349 if (sipper.getUid() == mPackageInfo.applicationInfo.uid) {
1358 protected void onPostExecute(Void result) {
1359 if (getActivity() == null) {
1367 * Elicit this class for testing. Test cannot be done in robolectric because it
1368 * invokes the new API.
1371 public static class PackageUtil {
1373 * Count how many users in device have installed package {@paramref packageName}
1375 public static int countPackageInUsers(PackageManager packageManager, UserManager
1376 userManager, String packageName) {
1377 final List<UserInfo> userInfos = userManager.getUsers(true);
1380 for (final UserInfo userInfo : userInfos) {
1382 // Use this API to check whether user has this package
1383 final ApplicationInfo info = packageManager.getApplicationInfoAsUser(
1384 packageName, PackageManager.GET_META_DATA, userInfo.id);
1385 if ((info.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
1388 } catch(NameNotFoundException e) {
1389 Log.e(TAG, "Package: " + packageName + " not found for user: " + userInfo.id);
1397 private static class DisableChanger extends AsyncTask<Object, Object, Object> {
1398 final PackageManager mPm;
1399 final WeakReference<InstalledAppDetails> mActivity;
1400 final ApplicationInfo mInfo;
1403 DisableChanger(InstalledAppDetails activity, ApplicationInfo info, int state) {
1405 mActivity = new WeakReference<InstalledAppDetails>(activity);
1411 protected Object doInBackground(Object... params) {
1412 mPm.setApplicationEnabledSetting(mInfo.packageName, mState, 0);
1417 private final LoaderCallbacks<ChartData> mDataCallbacks = new LoaderCallbacks<ChartData>() {
1420 public Loader<ChartData> onCreateLoader(int id, Bundle args) {
1421 return new ChartDataLoader(getActivity(), mStatsSession, args);
1425 public void onLoadFinished(Loader<ChartData> loader, ChartData data) {
1427 mDataPreference.setSummary(getDataSummary());
1431 public void onLoaderReset(Loader<ChartData> loader) {
1432 // Leave last result.
1436 private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() {
1438 public void onReceive(Context context, Intent intent) {
1439 final boolean enabled = getResultCode() != Activity.RESULT_CANCELED;
1440 Log.d(LOG_TAG, "Got broadcast response: Restart status for "
1441 + mAppEntry.info.packageName + " " + enabled);
1442 updateForceStopButton(enabled);
1446 private final PermissionsResultCallback mPermissionCallback
1447 = new PermissionsResultCallback() {
1449 public void onPermissionSummaryResult(int standardGrantedPermissionCount,
1450 int requestedPermissionCount, int additionalGrantedPermissionCount,
1451 List<CharSequence> grantedGroupLabels) {
1452 if (getActivity() == null) {
1455 final Resources res = getResources();
1456 CharSequence summary = null;
1458 if (requestedPermissionCount == 0) {
1459 summary = res.getString(
1460 R.string.runtime_permissions_summary_no_permissions_requested);
1461 mPermissionsPreference.setOnPreferenceClickListener(null);
1462 mPermissionsPreference.setEnabled(false);
1464 final ArrayList<CharSequence> list = new ArrayList<>(grantedGroupLabels);
1465 if (additionalGrantedPermissionCount > 0) {
1466 // N additional permissions.
1467 list.add(res.getQuantityString(
1468 R.plurals.runtime_permissions_additional_count,
1469 additionalGrantedPermissionCount, additionalGrantedPermissionCount));
1471 if (list.size() == 0) {
1472 summary = res.getString(
1473 R.string.runtime_permissions_summary_no_permissions_granted);
1475 summary = ListFormatter.getInstance().format(list);
1477 mPermissionsPreference.setOnPreferenceClickListener(InstalledAppDetails.this);
1478 mPermissionsPreference.setEnabled(true);
1480 mPermissionsPreference.setSummary(summary);