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 com.android.internal.telephony.ISms;
20 import com.android.internal.telephony.SmsUsageMonitor;
21 import com.android.settings.R;
22 import com.android.settings.SettingsActivity;
23 import com.android.settings.Utils;
24 import com.android.settings.applications.ApplicationsState.AppEntry;
26 import android.app.Activity;
27 import android.app.ActivityManager;
28 import android.app.AlertDialog;
29 import android.app.Dialog;
30 import android.app.DialogFragment;
31 import android.app.Fragment;
32 import android.app.INotificationManager;
33 import android.app.admin.DevicePolicyManager;
34 import android.appwidget.AppWidgetManager;
35 import android.content.BroadcastReceiver;
36 import android.content.ComponentName;
37 import android.content.Context;
38 import android.content.DialogInterface;
39 import android.content.Intent;
40 import android.content.IntentFilter;
41 import android.content.pm.ApplicationInfo;
42 import android.content.pm.IPackageDataObserver;
43 import android.content.pm.IPackageMoveObserver;
44 import android.content.pm.PackageInfo;
45 import android.content.pm.PackageManager;
46 import android.content.pm.ResolveInfo;
47 import android.content.pm.PackageManager.NameNotFoundException;
48 import android.content.res.Resources;
49 import android.hardware.usb.IUsbManager;
50 import android.net.Uri;
51 import android.os.AsyncTask;
52 import android.os.Bundle;
53 import android.os.Environment;
54 import android.os.Handler;
55 import android.os.IBinder;
56 import android.os.Message;
57 import android.os.RemoteException;
58 import android.os.ServiceManager;
59 import android.os.UserHandle;
60 import android.os.UserManager;
61 import android.text.SpannableString;
62 import android.text.TextUtils;
63 import android.text.format.Formatter;
64 import android.text.style.BulletSpan;
65 import android.util.Log;
67 import java.lang.ref.WeakReference;
68 import java.util.ArrayList;
69 import java.util.HashSet;
70 import java.util.List;
71 import android.view.LayoutInflater;
72 import android.view.Menu;
73 import android.view.MenuInflater;
74 import android.view.MenuItem;
75 import android.view.View;
76 import android.view.ViewGroup;
77 import android.widget.AdapterView;
78 import android.widget.AppSecurityPermissions;
79 import android.widget.ArrayAdapter;
80 import android.widget.Button;
81 import android.widget.CheckBox;
82 import android.widget.CompoundButton;
83 import android.widget.ImageView;
84 import android.widget.LinearLayout;
85 import android.widget.Spinner;
86 import android.widget.TextView;
89 * Activity to display application information from Settings. This activity presents
90 * extended information associated with a package like code, data, total size, permissions
91 * used by the application and also the set of default launchable activities.
92 * For system applications, an option to clear user data is displayed only if data size is > 0.
93 * System applications that do not want clear user data do not have this option.
94 * For non-system applications, there is no option to clear data. Instead there is an option to
95 * uninstall the application.
97 public class InstalledAppDetails extends Fragment
98 implements View.OnClickListener, CompoundButton.OnCheckedChangeListener,
99 ApplicationsState.Callbacks {
100 private static final String TAG="InstalledAppDetails";
101 private static final boolean localLOGV = false;
103 public static final String ARG_PACKAGE_NAME = "package";
105 private PackageManager mPm;
106 private UserManager mUserManager;
107 private IUsbManager mUsbManager;
108 private AppWidgetManager mAppWidgetManager;
109 private DevicePolicyManager mDpm;
110 private ISms mSmsManager;
111 private ApplicationsState mState;
112 private ApplicationsState.Session mSession;
113 private ApplicationsState.AppEntry mAppEntry;
114 private boolean mInitialized;
115 private boolean mShowUninstalled;
116 private PackageInfo mPackageInfo;
117 private CanBeOnSdCardChecker mCanBeOnSdCardChecker;
118 private View mRootView;
119 private Button mUninstallButton;
120 private View mMoreControlButtons;
121 private Button mSpecialDisableButton;
122 private boolean mMoveInProgress = false;
123 private boolean mUpdatedSysApp = false;
124 private Button mActivitiesButton;
125 private View mScreenCompatSection;
126 private CheckBox mAskCompatibilityCB;
127 private CheckBox mEnableCompatibilityCB;
128 private boolean mCanClearData = true;
129 private boolean mAppControlRestricted = false;
130 private TextView mAppVersion;
131 private TextView mTotalSize;
132 private TextView mAppSize;
133 private TextView mDataSize;
134 private TextView mExternalCodeSize;
135 private TextView mExternalDataSize;
136 private ClearUserDataObserver mClearDataObserver;
137 // Views related to cache info
138 private TextView mCacheSize;
139 private Button mClearCacheButton;
140 private ClearCacheObserver mClearCacheObserver;
141 private Button mForceStopButton;
142 private Button mClearDataButton;
143 private Button mMoveAppButton;
144 private CompoundButton mNotificationSwitch;
146 private PackageMoveObserver mPackageMoveObserver;
148 private final HashSet<String> mHomePackages = new HashSet<String>();
150 private boolean mDisableAfterUninstall;
152 private boolean mHaveSizes = false;
153 private long mLastCodeSize = -1;
154 private long mLastDataSize = -1;
155 private long mLastExternalCodeSize = -1;
156 private long mLastExternalDataSize = -1;
157 private long mLastCacheSize = -1;
158 private long mLastTotalSize = -1;
160 //internal constants used in Handler
161 private static final int OP_SUCCESSFUL = 1;
162 private static final int OP_FAILED = 2;
163 private static final int CLEAR_USER_DATA = 1;
164 private static final int CLEAR_CACHE = 3;
165 private static final int PACKAGE_MOVE = 4;
167 // invalid size value used initially and also when size retrieval through PackageManager
168 // fails for whatever reason
169 private static final int SIZE_INVALID = -1;
172 private CharSequence mInvalidSizeStr;
173 private CharSequence mComputingStr;
175 // Dialog identifiers used in showDialog
176 private static final int DLG_BASE = 0;
177 private static final int DLG_CLEAR_DATA = DLG_BASE + 1;
178 private static final int DLG_FACTORY_RESET = DLG_BASE + 2;
179 private static final int DLG_APP_NOT_FOUND = DLG_BASE + 3;
180 private static final int DLG_CANNOT_CLEAR_DATA = DLG_BASE + 4;
181 private static final int DLG_FORCE_STOP = DLG_BASE + 5;
182 private static final int DLG_MOVE_FAILED = DLG_BASE + 6;
183 private static final int DLG_DISABLE = DLG_BASE + 7;
184 private static final int DLG_DISABLE_NOTIFICATIONS = DLG_BASE + 8;
185 private static final int DLG_SPECIAL_DISABLE = DLG_BASE + 9;
188 public static final int UNINSTALL_ALL_USERS_MENU = 1;
190 // Result code identifiers
191 public static final int REQUEST_UNINSTALL = 1;
192 public static final int REQUEST_MANAGE_SPACE = 2;
194 private Handler mHandler = new Handler() {
195 public void handleMessage(Message msg) {
196 // If the fragment is gone, don't process any more messages.
197 if (getView() == null) {
201 case CLEAR_USER_DATA:
202 processClearMsg(msg);
206 mState.requestSize(mAppEntry.info.packageName);
217 class ClearUserDataObserver extends IPackageDataObserver.Stub {
218 public void onRemoveCompleted(final String packageName, final boolean succeeded) {
219 final Message msg = mHandler.obtainMessage(CLEAR_USER_DATA);
220 msg.arg1 = succeeded?OP_SUCCESSFUL:OP_FAILED;
221 mHandler.sendMessage(msg);
225 class ClearCacheObserver extends IPackageDataObserver.Stub {
226 public void onRemoveCompleted(final String packageName, final boolean succeeded) {
227 final Message msg = mHandler.obtainMessage(CLEAR_CACHE);
228 msg.arg1 = succeeded ? OP_SUCCESSFUL:OP_FAILED;
229 mHandler.sendMessage(msg);
233 class PackageMoveObserver extends IPackageMoveObserver.Stub {
234 public void packageMoved(String packageName, int returnCode) throws RemoteException {
235 final Message msg = mHandler.obtainMessage(PACKAGE_MOVE);
236 msg.arg1 = returnCode;
237 mHandler.sendMessage(msg);
241 private String getSizeStr(long size) {
242 if (size == SIZE_INVALID) {
243 return mInvalidSizeStr.toString();
245 return Formatter.formatFileSize(getActivity(), size);
248 private void initDataButtons() {
249 // If the app doesn't have its own space management UI
250 // And it's a system app that doesn't allow clearing user data or is an active admin
251 // Then disable the Clear Data button.
252 if (mAppEntry.info.manageSpaceActivityName == null
253 && ((mAppEntry.info.flags&(ApplicationInfo.FLAG_SYSTEM
254 | ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA))
255 == ApplicationInfo.FLAG_SYSTEM
256 || mDpm.packageHasActiveAdmins(mPackageInfo.packageName))) {
257 mClearDataButton.setText(R.string.clear_user_data_text);
258 mClearDataButton.setEnabled(false);
259 mCanClearData = false;
261 if (mAppEntry.info.manageSpaceActivityName != null) {
262 mClearDataButton.setText(R.string.manage_space_text);
264 mClearDataButton.setText(R.string.clear_user_data_text);
266 mClearDataButton.setOnClickListener(this);
269 if (mAppControlRestricted) {
270 mClearDataButton.setEnabled(false);
274 private CharSequence getMoveErrMsg(int errCode) {
276 case PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE:
277 return getActivity().getString(R.string.insufficient_storage);
278 case PackageManager.MOVE_FAILED_DOESNT_EXIST:
279 return getActivity().getString(R.string.does_not_exist);
280 case PackageManager.MOVE_FAILED_FORWARD_LOCKED:
281 return getActivity().getString(R.string.app_forward_locked);
282 case PackageManager.MOVE_FAILED_INVALID_LOCATION:
283 return getActivity().getString(R.string.invalid_location);
284 case PackageManager.MOVE_FAILED_SYSTEM_PACKAGE:
285 return getActivity().getString(R.string.system_package);
286 case PackageManager.MOVE_FAILED_INTERNAL_ERROR:
292 private void initMoveButton() {
293 if (Environment.isExternalStorageEmulated()) {
294 mMoveAppButton.setVisibility(View.INVISIBLE);
297 boolean dataOnly = false;
298 dataOnly = (mPackageInfo == null) && (mAppEntry != null);
299 boolean moveDisable = true;
301 mMoveAppButton.setText(R.string.move_app);
302 } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
303 mMoveAppButton.setText(R.string.move_app_to_internal);
304 // Always let apps move to internal storage from sdcard.
307 mMoveAppButton.setText(R.string.move_app_to_sdcard);
308 mCanBeOnSdCardChecker.init();
309 moveDisable = !mCanBeOnSdCardChecker.check(mAppEntry.info);
311 if (moveDisable || mAppControlRestricted) {
312 mMoveAppButton.setEnabled(false);
314 mMoveAppButton.setOnClickListener(this);
315 mMoveAppButton.setEnabled(true);
319 private boolean handleDisableable(Button button) {
320 boolean disableable = false;
321 // Try to prevent the user from bricking their phone
322 // by not allowing disabling of apps signed with the
323 // system cert and any launcher app in the system.
324 if (mHomePackages.contains(mAppEntry.info.packageName)
325 || Utils.isSystemPackage(mPm, mPackageInfo)) {
326 // Disable button for core system applications.
327 button.setText(R.string.disable_text);
328 } else if (mAppEntry.info.enabled) {
329 button.setText(R.string.disable_text);
332 button.setText(R.string.enable_text);
339 private void initUninstallButtons() {
340 mUpdatedSysApp = (mAppEntry.info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
341 final boolean isBundled = (mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
342 boolean enabled = true;
343 if (mUpdatedSysApp) {
344 mUninstallButton.setText(R.string.app_factory_reset);
345 boolean showSpecialDisable = false;
347 showSpecialDisable = handleDisableable(mSpecialDisableButton);
348 mSpecialDisableButton.setOnClickListener(this);
350 if (mAppControlRestricted) {
351 showSpecialDisable = false;
353 mMoreControlButtons.setVisibility(showSpecialDisable ? View.VISIBLE : View.GONE);
355 mMoreControlButtons.setVisibility(View.GONE);
357 enabled = handleDisableable(mUninstallButton);
358 } else if ((mPackageInfo.applicationInfo.flags
359 & ApplicationInfo.FLAG_INSTALLED) == 0
360 && mUserManager.getUsers().size() >= 2) {
361 // When we have multiple users, there is a separate menu
362 // to uninstall for all users.
363 mUninstallButton.setText(R.string.uninstall_text);
366 mUninstallButton.setText(R.string.uninstall_text);
369 // If this is a device admin, it can't be uninstalled or disabled.
370 // We do this here so the text of the button is still set correctly.
371 if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
375 // Home apps need special handling. Bundled ones we don't risk downgrading
376 // because that can interfere with home-key resolution. Furthermore, we
377 // can't allow uninstallation of the only home app, and we don't want to
378 // allow uninstallation of an explicitly preferred one -- the user can go
379 // to Home settings and pick a different one, after which we'll permit
380 // uninstallation of the now-not-default one.
381 if (enabled && mHomePackages.contains(mPackageInfo.packageName)) {
385 ArrayList<ResolveInfo> homeActivities = new ArrayList<ResolveInfo>();
386 ComponentName currentDefaultHome = mPm.getHomeActivities(homeActivities);
387 if (currentDefaultHome == null) {
388 // No preferred default, so permit uninstall only when
389 // there is more than one candidate
390 enabled = (mHomePackages.size() > 1);
392 // There is an explicit default home app -- forbid uninstall of
393 // that one, but permit it for installed-but-inactive ones.
394 enabled = !mPackageInfo.packageName.equals(currentDefaultHome.getPackageName());
399 if (mAppControlRestricted) {
403 mUninstallButton.setEnabled(enabled);
406 mUninstallButton.setOnClickListener(this);
410 private void initNotificationButton() {
411 INotificationManager nm = INotificationManager.Stub.asInterface(
412 ServiceManager.getService(Context.NOTIFICATION_SERVICE));
413 boolean enabled = true; // default on
415 enabled = nm.areNotificationsEnabledForPackage(mAppEntry.info.packageName,
417 } catch (android.os.RemoteException ex) {
418 // this does not bode well
420 mNotificationSwitch.setChecked(enabled);
421 if (Utils.isSystemPackage(mPm, mPackageInfo)) {
422 mNotificationSwitch.setEnabled(false);
423 } else if ((mPackageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) == 0) {
424 // App is not installed on the current user
425 mNotificationSwitch.setEnabled(false);
427 mNotificationSwitch.setEnabled(true);
428 mNotificationSwitch.setOnCheckedChangeListener(this);
432 /** Called when the activity is first created. */
434 public void onCreate(Bundle icicle) {
435 super.onCreate(icicle);
437 mState = ApplicationsState.getInstance(getActivity().getApplication());
438 mSession = mState.newSession(this);
439 mPm = getActivity().getPackageManager();
440 mUserManager = (UserManager)getActivity().getSystemService(Context.USER_SERVICE);
441 IBinder b = ServiceManager.getService(Context.USB_SERVICE);
442 mUsbManager = IUsbManager.Stub.asInterface(b);
443 mAppWidgetManager = AppWidgetManager.getInstance(getActivity());
444 mDpm = (DevicePolicyManager)getActivity().getSystemService(Context.DEVICE_POLICY_SERVICE);
445 mSmsManager = ISms.Stub.asInterface(ServiceManager.getService("isms"));
447 mCanBeOnSdCardChecker = new CanBeOnSdCardChecker();
449 // Need to make sure we have loaded applications at this point.
454 setHasOptionsMenu(true);
458 public View onCreateView(
459 LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
460 final View view = inflater.inflate(R.layout.installed_app_details, container, false);
462 final ViewGroup allDetails = (ViewGroup) view.findViewById(R.id.all_details);
463 Utils.forceCustomPadding(allDetails, true /* additive padding */);
466 mComputingStr = getActivity().getText(R.string.computing_size);
468 // Set default values on sizes
469 mTotalSize = (TextView) view.findViewById(R.id.total_size_text);
470 mAppSize = (TextView) view.findViewById(R.id.application_size_text);
471 mDataSize = (TextView) view.findViewById(R.id.data_size_text);
472 mExternalCodeSize = (TextView) view.findViewById(R.id.external_code_size_text);
473 mExternalDataSize = (TextView) view.findViewById(R.id.external_data_size_text);
475 if (Environment.isExternalStorageEmulated()) {
476 ((View)mExternalCodeSize.getParent()).setVisibility(View.GONE);
477 ((View)mExternalDataSize.getParent()).setVisibility(View.GONE);
480 // Get Control button panel
481 View btnPanel = view.findViewById(R.id.control_buttons_panel);
482 mForceStopButton = (Button) btnPanel.findViewById(R.id.left_button);
483 mForceStopButton.setText(R.string.force_stop);
484 mUninstallButton = (Button) btnPanel.findViewById(R.id.right_button);
485 mForceStopButton.setEnabled(false);
487 // Get More Control button panel
488 mMoreControlButtons = view.findViewById(R.id.more_control_buttons_panel);
489 mMoreControlButtons.findViewById(R.id.left_button).setVisibility(View.INVISIBLE);
490 mSpecialDisableButton = (Button) mMoreControlButtons.findViewById(R.id.right_button);
491 mMoreControlButtons.setVisibility(View.GONE);
493 // Initialize clear data and move install location buttons
494 View data_buttons_panel = view.findViewById(R.id.data_buttons_panel);
495 mClearDataButton = (Button) data_buttons_panel.findViewById(R.id.right_button);
496 mMoveAppButton = (Button) data_buttons_panel.findViewById(R.id.left_button);
499 mCacheSize = (TextView) view.findViewById(R.id.cache_size_text);
500 mClearCacheButton = (Button) view.findViewById(R.id.clear_cache_button);
502 mActivitiesButton = (Button) view.findViewById(R.id.clear_activities_button);
504 // Screen compatibility control
505 mScreenCompatSection = view.findViewById(R.id.screen_compatibility_section);
506 mAskCompatibilityCB = (CheckBox) view.findViewById(R.id.ask_compatibility_cb);
507 mEnableCompatibilityCB = (CheckBox) view.findViewById(R.id.enable_compatibility_cb);
509 mNotificationSwitch = (CompoundButton) view.findViewById(R.id.notification_switch);
515 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
516 menu.add(0, UNINSTALL_ALL_USERS_MENU, 1, R.string.uninstall_all_users_text)
517 .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
521 public void onPrepareOptionsMenu(Menu menu) {
522 boolean showIt = true;
523 if (mUpdatedSysApp) {
525 } else if (mAppEntry == null) {
527 } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
529 } else if (mPackageInfo == null || mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
531 } else if (UserHandle.myUserId() != 0) {
533 } else if (mUserManager.getUsers().size() < 2) {
536 menu.findItem(UNINSTALL_ALL_USERS_MENU).setVisible(showIt);
540 public boolean onOptionsItemSelected(MenuItem item) {
541 int menuId = item.getItemId();
542 if (menuId == UNINSTALL_ALL_USERS_MENU) {
543 uninstallPkg(mAppEntry.info.packageName, true, false);
550 public void onActivityResult(int requestCode, int resultCode, Intent data) {
551 super.onActivityResult(requestCode, resultCode, data);
552 if (requestCode == REQUEST_UNINSTALL) {
553 if (mDisableAfterUninstall) {
554 mDisableAfterUninstall = false;
556 ApplicationInfo ainfo = getActivity().getPackageManager().getApplicationInfo(
557 mAppEntry.info.packageName, PackageManager.GET_UNINSTALLED_PACKAGES
558 | PackageManager.GET_DISABLED_COMPONENTS);
559 if ((ainfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0) {
560 new DisableChanger(this, mAppEntry.info,
561 PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER)
562 .execute((Object)null);
564 } catch (NameNotFoundException e) {
568 setIntentAndFinish(true, true);
573 // Utility method to set application label and icon.
574 private void setAppLabelAndIcon(PackageInfo pkgInfo) {
575 final View appSnippet = mRootView.findViewById(R.id.app_snippet);
576 appSnippet.setPaddingRelative(0, appSnippet.getPaddingTop(), 0, appSnippet.getPaddingBottom());
578 ImageView icon = (ImageView) appSnippet.findViewById(R.id.app_icon);
579 mState.ensureIcon(mAppEntry);
580 icon.setImageDrawable(mAppEntry.icon);
581 // Set application name.
582 TextView label = (TextView) appSnippet.findViewById(R.id.app_name);
583 label.setText(mAppEntry.label);
584 // Version number of application
585 mAppVersion = (TextView) appSnippet.findViewById(R.id.app_size);
587 if (pkgInfo != null && pkgInfo.versionName != null) {
588 mAppVersion.setVisibility(View.VISIBLE);
589 mAppVersion.setText(getActivity().getString(R.string.version_text,
590 String.valueOf(pkgInfo.versionName)));
592 mAppVersion.setVisibility(View.INVISIBLE);
597 public void onResume() {
600 mAppControlRestricted = mUserManager.hasUserRestriction(UserManager.DISALLOW_APPS_CONTROL);
603 setIntentAndFinish(true, true);
608 public void onPause() {
614 public void onDestroyView() {
615 super.onDestroyView();
620 public void onAllSizesComputed() {
624 public void onPackageIconChanged() {
628 public void onPackageListChanged() {
633 public void onRebuildComplete(ArrayList<AppEntry> apps) {
637 public void onPackageSizeChanged(String packageName) {
638 if (packageName.equals(mAppEntry.info.packageName)) {
644 public void onRunningStateChanged(boolean running) {
647 private String retrieveAppEntry() {
648 final Bundle args = getArguments();
649 String packageName = (args != null) ? args.getString(ARG_PACKAGE_NAME) : null;
650 if (packageName == null) {
651 Intent intent = (args == null) ?
652 getActivity().getIntent() : (Intent) args.getParcelable("intent");
653 if (intent != null) {
654 packageName = intent.getData().getSchemeSpecificPart();
657 mAppEntry = mState.getEntry(packageName);
658 if (mAppEntry != null) {
659 // Get application info again to refresh changed properties of application
661 mPackageInfo = mPm.getPackageInfo(mAppEntry.info.packageName,
662 PackageManager.GET_DISABLED_COMPONENTS |
663 PackageManager.GET_UNINSTALLED_PACKAGES |
664 PackageManager.GET_SIGNATURES);
665 } catch (NameNotFoundException e) {
666 Log.e(TAG, "Exception when retrieving package:" + mAppEntry.info.packageName, e);
669 Log.w(TAG, "Missing AppEntry; maybe reinstalling?");
676 private boolean signaturesMatch(String pkg1, String pkg2) {
677 if (pkg1 != null && pkg2 != null) {
679 final int match = mPm.checkSignatures(pkg1, pkg2);
680 if (match >= PackageManager.SIGNATURE_MATCH) {
683 } catch (Exception e) {
684 // e.g. named alternate package not found during lookup;
685 // this is an expected case sometimes
691 private boolean refreshUi() {
692 if (mMoveInProgress) {
695 final String packageName = retrieveAppEntry();
697 if (mAppEntry == null) {
698 return false; // onCreate must have failed, make sure to exit
701 if (mPackageInfo == null) {
702 return false; // onCreate must have failed, make sure to exit
705 // Get list of "home" apps and trace through any meta-data references
706 List<ResolveInfo> homeActivities = new ArrayList<ResolveInfo>();
707 mPm.getHomeActivities(homeActivities);
708 mHomePackages.clear();
709 for (int i = 0; i< homeActivities.size(); i++) {
710 ResolveInfo ri = homeActivities.get(i);
711 final String activityPkg = ri.activityInfo.packageName;
712 mHomePackages.add(activityPkg);
714 // Also make sure to include anything proxying for the home app
715 final Bundle metadata = ri.activityInfo.metaData;
716 if (metadata != null) {
717 final String metaPkg = metadata.getString(ActivityManager.META_HOME_ALTERNATE);
718 if (signaturesMatch(metaPkg, activityPkg)) {
719 mHomePackages.add(metaPkg);
724 // Get list of preferred activities
725 List<ComponentName> prefActList = new ArrayList<ComponentName>();
727 // Intent list cannot be null. so pass empty list
728 List<IntentFilter> intentList = new ArrayList<IntentFilter>();
729 mPm.getPreferredActivities(intentList, prefActList, packageName);
731 Log.i(TAG, "Have " + prefActList.size() + " number of activities in preferred list");
732 boolean hasUsbDefaults = false;
734 if (mUsbManager != null) {
735 hasUsbDefaults = mUsbManager.hasDefaults(packageName, UserHandle.myUserId());
737 } catch (RemoteException e) {
738 Log.e(TAG, "mUsbManager.hasDefaults", e);
740 boolean hasBindAppWidgetPermission =
741 mAppWidgetManager.hasBindAppWidgetPermission(mAppEntry.info.packageName);
743 TextView autoLaunchTitleView = (TextView) mRootView.findViewById(R.id.auto_launch_title);
744 TextView autoLaunchView = (TextView) mRootView.findViewById(R.id.auto_launch);
745 boolean autoLaunchEnabled = prefActList.size() > 0 || hasUsbDefaults;
746 if (!autoLaunchEnabled && !hasBindAppWidgetPermission) {
747 resetLaunchDefaultsUi(autoLaunchTitleView, autoLaunchView);
749 boolean useBullets = hasBindAppWidgetPermission && autoLaunchEnabled;
751 if (hasBindAppWidgetPermission) {
752 autoLaunchTitleView.setText(R.string.auto_launch_label_generic);
754 autoLaunchTitleView.setText(R.string.auto_launch_label);
757 CharSequence text = null;
758 int bulletIndent = getResources()
759 .getDimensionPixelSize(R.dimen.installed_app_details_bullet_offset);
760 if (autoLaunchEnabled) {
761 CharSequence autoLaunchEnableText = getText(R.string.auto_launch_enable_text);
762 SpannableString s = new SpannableString(autoLaunchEnableText);
764 s.setSpan(new BulletSpan(bulletIndent), 0, autoLaunchEnableText.length(), 0);
766 text = (text == null) ?
767 TextUtils.concat(s, "\n") : TextUtils.concat(text, "\n", s, "\n");
769 if (hasBindAppWidgetPermission) {
770 CharSequence alwaysAllowBindAppWidgetsText =
771 getText(R.string.always_allow_bind_appwidgets_text);
772 SpannableString s = new SpannableString(alwaysAllowBindAppWidgetsText);
774 s.setSpan(new BulletSpan(bulletIndent),
775 0, alwaysAllowBindAppWidgetsText.length(), 0);
777 text = (text == null) ?
778 TextUtils.concat(s, "\n") : TextUtils.concat(text, "\n", s, "\n");
780 autoLaunchView.setText(text);
781 mActivitiesButton.setEnabled(true);
782 mActivitiesButton.setOnClickListener(this);
785 // Screen compatibility section.
786 ActivityManager am = (ActivityManager)
787 getActivity().getSystemService(Context.ACTIVITY_SERVICE);
788 int compatMode = am.getPackageScreenCompatMode(packageName);
789 // For now these are always off; this is the old UI model which we
790 // are no longer using.
791 if (false && (compatMode == ActivityManager.COMPAT_MODE_DISABLED
792 || compatMode == ActivityManager.COMPAT_MODE_ENABLED)) {
793 mScreenCompatSection.setVisibility(View.VISIBLE);
794 mAskCompatibilityCB.setChecked(am.getPackageAskScreenCompat(packageName));
795 mAskCompatibilityCB.setOnCheckedChangeListener(this);
796 mEnableCompatibilityCB.setChecked(compatMode == ActivityManager.COMPAT_MODE_ENABLED);
797 mEnableCompatibilityCB.setOnCheckedChangeListener(this);
799 mScreenCompatSection.setVisibility(View.GONE);
802 // Security permissions section
803 LinearLayout permsView = (LinearLayout) mRootView.findViewById(R.id.permissions_section);
804 AppSecurityPermissions asp = new AppSecurityPermissions(getActivity(), packageName);
805 int premiumSmsPermission = getPremiumSmsPermission(packageName);
806 // Premium SMS permission implies the app also has SEND_SMS permission, so the original
807 // application permissions list doesn't have to be shown/hidden separately. The premium
808 // SMS subsection should only be visible if the app has tried to send to a premium SMS.
809 if (asp.getPermissionCount() > 0
810 || premiumSmsPermission != SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) {
811 permsView.setVisibility(View.VISIBLE);
813 permsView.setVisibility(View.GONE);
815 // Premium SMS permission subsection
816 TextView securityBillingDesc = (TextView) permsView.findViewById(
817 R.id.security_settings_billing_desc);
818 LinearLayout securityBillingList = (LinearLayout) permsView.findViewById(
819 R.id.security_settings_billing_list);
820 if (premiumSmsPermission != SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) {
821 // Show the premium SMS permission selector
822 securityBillingDesc.setVisibility(View.VISIBLE);
823 securityBillingList.setVisibility(View.VISIBLE);
824 Spinner spinner = (Spinner) permsView.findViewById(
825 R.id.security_settings_premium_sms_list);
826 ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(getActivity(),
827 R.array.security_settings_premium_sms_values,
828 android.R.layout.simple_spinner_item);
829 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
830 spinner.setAdapter(adapter);
831 // List items are in the same order as SmsUsageMonitor constants, offset by 1.
832 spinner.setSelection(premiumSmsPermission - 1);
833 spinner.setOnItemSelectedListener(new PremiumSmsSelectionListener(
834 packageName, mSmsManager));
836 // Hide the premium SMS permission selector
837 securityBillingDesc.setVisibility(View.GONE);
838 securityBillingList.setVisibility(View.GONE);
840 // App permissions subsection
841 if (asp.getPermissionCount() > 0) {
842 // Make the security sections header visible
843 LinearLayout securityList = (LinearLayout) permsView.findViewById(
844 R.id.security_settings_list);
845 securityList.removeAllViews();
846 securityList.addView(asp.getPermissionsViewWithRevokeButtons());
847 // If this app is running under a shared user ID with other apps,
848 // update the description to explain this.
849 String[] packages = mPm.getPackagesForUid(mPackageInfo.applicationInfo.uid);
850 if (packages != null && packages.length > 1) {
851 ArrayList<CharSequence> pnames = new ArrayList<CharSequence>();
852 for (int i=0; i<packages.length; i++) {
853 String pkg = packages[i];
854 if (mPackageInfo.packageName.equals(pkg)) {
858 ApplicationInfo ainfo = mPm.getApplicationInfo(pkg, 0);
859 pnames.add(ainfo.loadLabel(mPm));
860 } catch (PackageManager.NameNotFoundException e) {
863 final int N = pnames.size();
865 final Resources res = getActivity().getResources();
868 appListStr = pnames.get(0).toString();
870 appListStr = res.getString(R.string.join_two_items, pnames.get(0),
873 appListStr = pnames.get(N-2).toString();
874 for (int i=N-3; i>=0; i--) {
875 appListStr = res.getString(i == 0 ? R.string.join_many_items_first
876 : R.string.join_many_items_middle, pnames.get(i), appListStr);
878 appListStr = res.getString(R.string.join_many_items_last,
879 appListStr, pnames.get(N-1));
881 TextView descr = (TextView) mRootView.findViewById(
882 R.id.security_settings_desc);
883 descr.setText(res.getString(R.string.security_settings_desc_multi,
884 mPackageInfo.applicationInfo.loadLabel(mPm), appListStr));
890 setAppLabelAndIcon(mPackageInfo);
895 // First time init: are we displaying an uninstalled app?
897 mShowUninstalled = (mAppEntry.info.flags&ApplicationInfo.FLAG_INSTALLED) == 0;
899 // All other times: if the app no longer exists then we want
902 ApplicationInfo ainfo = getActivity().getPackageManager().getApplicationInfo(
903 mAppEntry.info.packageName, PackageManager.GET_UNINSTALLED_PACKAGES
904 | PackageManager.GET_DISABLED_COMPONENTS);
905 if (!mShowUninstalled) {
906 // If we did not start out with the app uninstalled, then
907 // it transitioning to the uninstalled state for the current
908 // user means we should go away as well.
909 return (ainfo.flags&ApplicationInfo.FLAG_INSTALLED) != 0;
911 } catch (NameNotFoundException e) {
919 private static class PremiumSmsSelectionListener implements AdapterView.OnItemSelectedListener {
920 private final String mPackageName;
921 private final ISms mSmsManager;
923 PremiumSmsSelectionListener(String packageName, ISms smsManager) {
924 mPackageName = packageName;
925 mSmsManager = smsManager;
929 public void onItemSelected(AdapterView<?> parent, View view, int position,
931 if (position >= 0 && position < 3) {
932 Log.d(TAG, "Selected premium SMS policy " + position);
933 setPremiumSmsPermission(mPackageName, (position + 1));
935 Log.e(TAG, "Error: unknown premium SMS policy " + position);
940 public void onNothingSelected(AdapterView<?> parent) {
944 private void setPremiumSmsPermission(String packageName, int permission) {
946 if (mSmsManager != null) {
947 mSmsManager.setPremiumSmsPermission(packageName, permission);
949 } catch (RemoteException ex) {
955 private void resetLaunchDefaultsUi(TextView title, TextView autoLaunchView) {
956 title.setText(R.string.auto_launch_label);
957 autoLaunchView.setText(R.string.auto_launch_disable_text);
958 // Disable clear activities button
959 mActivitiesButton.setEnabled(false);
962 private void setIntentAndFinish(boolean finish, boolean appChanged) {
963 if(localLOGV) Log.i(TAG, "appChanged="+appChanged);
964 Intent intent = new Intent();
965 intent.putExtra(ManageApplications.APP_CHG, appChanged);
966 SettingsActivity sa = (SettingsActivity)getActivity();
967 sa.finishPreferencePanel(this, Activity.RESULT_OK, intent);
970 private void refreshSizeInfo() {
971 if (mAppEntry.size == ApplicationsState.SIZE_INVALID
972 || mAppEntry.size == ApplicationsState.SIZE_UNKNOWN) {
973 mLastCodeSize = mLastDataSize = mLastCacheSize = mLastTotalSize = -1;
975 mAppSize.setText(mComputingStr);
976 mDataSize.setText(mComputingStr);
977 mCacheSize.setText(mComputingStr);
978 mTotalSize.setText(mComputingStr);
980 mClearDataButton.setEnabled(false);
981 mClearCacheButton.setEnabled(false);
985 long codeSize = mAppEntry.codeSize;
986 long dataSize = mAppEntry.dataSize;
987 if (Environment.isExternalStorageEmulated()) {
988 codeSize += mAppEntry.externalCodeSize;
989 dataSize += mAppEntry.externalDataSize;
991 if (mLastExternalCodeSize != mAppEntry.externalCodeSize) {
992 mLastExternalCodeSize = mAppEntry.externalCodeSize;
993 mExternalCodeSize.setText(getSizeStr(mAppEntry.externalCodeSize));
995 if (mLastExternalDataSize != mAppEntry.externalDataSize) {
996 mLastExternalDataSize = mAppEntry.externalDataSize;
997 mExternalDataSize.setText(getSizeStr( mAppEntry.externalDataSize));
1000 if (mLastCodeSize != codeSize) {
1001 mLastCodeSize = codeSize;
1002 mAppSize.setText(getSizeStr(codeSize));
1004 if (mLastDataSize != dataSize) {
1005 mLastDataSize = dataSize;
1006 mDataSize.setText(getSizeStr(dataSize));
1008 long cacheSize = mAppEntry.cacheSize + mAppEntry.externalCacheSize;
1009 if (mLastCacheSize != cacheSize) {
1010 mLastCacheSize = cacheSize;
1011 mCacheSize.setText(getSizeStr(cacheSize));
1013 if (mLastTotalSize != mAppEntry.size) {
1014 mLastTotalSize = mAppEntry.size;
1015 mTotalSize.setText(getSizeStr(mAppEntry.size));
1018 if ((mAppEntry.dataSize+ mAppEntry.externalDataSize) <= 0 || !mCanClearData) {
1019 mClearDataButton.setEnabled(false);
1021 mClearDataButton.setEnabled(true);
1022 mClearDataButton.setOnClickListener(this);
1024 if (cacheSize <= 0) {
1025 mClearCacheButton.setEnabled(false);
1027 mClearCacheButton.setEnabled(true);
1028 mClearCacheButton.setOnClickListener(this);
1031 if (mAppControlRestricted) {
1032 mClearCacheButton.setEnabled(false);
1033 mClearDataButton.setEnabled(false);
1038 * Private method to handle clear message notification from observer when
1039 * the async operation from PackageManager is complete
1041 private void processClearMsg(Message msg) {
1042 int result = msg.arg1;
1043 String packageName = mAppEntry.info.packageName;
1044 mClearDataButton.setText(R.string.clear_user_data_text);
1045 if(result == OP_SUCCESSFUL) {
1046 Log.i(TAG, "Cleared user data for package : "+packageName);
1047 mState.requestSize(mAppEntry.info.packageName);
1049 mClearDataButton.setEnabled(true);
1054 private void refreshButtons() {
1055 if (!mMoveInProgress) {
1056 initUninstallButtons();
1059 initNotificationButton();
1061 mMoveAppButton.setText(R.string.moving);
1062 mMoveAppButton.setEnabled(false);
1063 mUninstallButton.setEnabled(false);
1064 mSpecialDisableButton.setEnabled(false);
1068 private void processMoveMsg(Message msg) {
1069 int result = msg.arg1;
1070 String packageName = mAppEntry.info.packageName;
1071 // Refresh the button attributes.
1072 mMoveInProgress = false;
1073 if (result == PackageManager.MOVE_SUCCEEDED) {
1074 Log.i(TAG, "Moved resources for " + packageName);
1075 // Refresh size information again.
1076 mState.requestSize(mAppEntry.info.packageName);
1078 showDialogInner(DLG_MOVE_FAILED, result);
1084 * Private method to initiate clearing user data when the user clicks the clear data
1085 * button for a system package
1087 private void initiateClearUserData() {
1088 mClearDataButton.setEnabled(false);
1089 // Invoke uninstall or clear user data based on sysPackage
1090 String packageName = mAppEntry.info.packageName;
1091 Log.i(TAG, "Clearing user data for package : " + packageName);
1092 if (mClearDataObserver == null) {
1093 mClearDataObserver = new ClearUserDataObserver();
1095 ActivityManager am = (ActivityManager)
1096 getActivity().getSystemService(Context.ACTIVITY_SERVICE);
1097 boolean res = am.clearApplicationUserData(packageName, mClearDataObserver);
1099 // Clearing data failed for some obscure reason. Just log error for now
1100 Log.i(TAG, "Couldnt clear application user data for package:"+packageName);
1101 showDialogInner(DLG_CANNOT_CLEAR_DATA, 0);
1103 mClearDataButton.setText(R.string.recompute_size);
1107 private void showDialogInner(int id, int moveErrorCode) {
1108 DialogFragment newFragment = MyAlertDialogFragment.newInstance(id, moveErrorCode);
1109 newFragment.setTargetFragment(this, 0);
1110 newFragment.show(getFragmentManager(), "dialog " + id);
1113 public static class MyAlertDialogFragment extends DialogFragment {
1115 public static MyAlertDialogFragment newInstance(int id, int moveErrorCode) {
1116 MyAlertDialogFragment frag = new MyAlertDialogFragment();
1117 Bundle args = new Bundle();
1118 args.putInt("id", id);
1119 args.putInt("moveError", moveErrorCode);
1120 frag.setArguments(args);
1124 InstalledAppDetails getOwner() {
1125 return (InstalledAppDetails)getTargetFragment();
1129 public Dialog onCreateDialog(Bundle savedInstanceState) {
1130 int id = getArguments().getInt("id");
1131 int moveErrorCode = getArguments().getInt("moveError");
1133 case DLG_CLEAR_DATA:
1134 return new AlertDialog.Builder(getActivity())
1135 .setTitle(getActivity().getText(R.string.clear_data_dlg_title))
1136 .setMessage(getActivity().getText(R.string.clear_data_dlg_text))
1137 .setPositiveButton(R.string.dlg_ok,
1138 new DialogInterface.OnClickListener() {
1139 public void onClick(DialogInterface dialog, int which) {
1140 // Clear user data here
1141 getOwner().initiateClearUserData();
1144 .setNegativeButton(R.string.dlg_cancel, null)
1146 case DLG_FACTORY_RESET:
1147 return new AlertDialog.Builder(getActivity())
1148 .setTitle(getActivity().getText(R.string.app_factory_reset_dlg_title))
1149 .setMessage(getActivity().getText(R.string.app_factory_reset_dlg_text))
1150 .setPositiveButton(R.string.dlg_ok,
1151 new DialogInterface.OnClickListener() {
1152 public void onClick(DialogInterface dialog, int which) {
1153 // Clear user data here
1154 getOwner().uninstallPkg(getOwner().mAppEntry.info.packageName,
1158 .setNegativeButton(R.string.dlg_cancel, null)
1160 case DLG_APP_NOT_FOUND:
1161 return new AlertDialog.Builder(getActivity())
1162 .setTitle(getActivity().getText(R.string.app_not_found_dlg_title))
1163 .setMessage(getActivity().getText(R.string.app_not_found_dlg_title))
1164 .setNeutralButton(getActivity().getText(R.string.dlg_ok),
1165 new DialogInterface.OnClickListener() {
1166 public void onClick(DialogInterface dialog, int which) {
1167 //force to recompute changed value
1168 getOwner().setIntentAndFinish(true, true);
1172 case DLG_CANNOT_CLEAR_DATA:
1173 return new AlertDialog.Builder(getActivity())
1174 .setTitle(getActivity().getText(R.string.clear_failed_dlg_title))
1175 .setMessage(getActivity().getText(R.string.clear_failed_dlg_text))
1176 .setNeutralButton(R.string.dlg_ok,
1177 new DialogInterface.OnClickListener() {
1178 public void onClick(DialogInterface dialog, int which) {
1179 getOwner().mClearDataButton.setEnabled(false);
1180 //force to recompute changed value
1181 getOwner().setIntentAndFinish(false, false);
1185 case DLG_FORCE_STOP:
1186 return new AlertDialog.Builder(getActivity())
1187 .setTitle(getActivity().getText(R.string.force_stop_dlg_title))
1188 .setMessage(getActivity().getText(R.string.force_stop_dlg_text))
1189 .setPositiveButton(R.string.dlg_ok,
1190 new DialogInterface.OnClickListener() {
1191 public void onClick(DialogInterface dialog, int which) {
1193 getOwner().forceStopPackage(getOwner().mAppEntry.info.packageName);
1196 .setNegativeButton(R.string.dlg_cancel, null)
1198 case DLG_MOVE_FAILED:
1199 CharSequence msg = getActivity().getString(R.string.move_app_failed_dlg_text,
1200 getOwner().getMoveErrMsg(moveErrorCode));
1201 return new AlertDialog.Builder(getActivity())
1202 .setTitle(getActivity().getText(R.string.move_app_failed_dlg_title))
1204 .setNeutralButton(R.string.dlg_ok, null)
1207 return new AlertDialog.Builder(getActivity())
1208 .setTitle(getActivity().getText(R.string.app_disable_dlg_title))
1209 .setMessage(getActivity().getText(R.string.app_disable_dlg_text))
1210 .setPositiveButton(R.string.dlg_ok,
1211 new DialogInterface.OnClickListener() {
1212 public void onClick(DialogInterface dialog, int which) {
1214 new DisableChanger(getOwner(), getOwner().mAppEntry.info,
1215 PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER)
1216 .execute((Object)null);
1219 .setNegativeButton(R.string.dlg_cancel, null)
1221 case DLG_DISABLE_NOTIFICATIONS:
1222 return new AlertDialog.Builder(getActivity())
1223 .setTitle(getActivity().getText(R.string.app_disable_notifications_dlg_title))
1224 .setMessage(getActivity().getText(R.string.app_disable_notifications_dlg_text))
1225 .setPositiveButton(R.string.dlg_ok,
1226 new DialogInterface.OnClickListener() {
1227 public void onClick(DialogInterface dialog, int which) {
1228 // Disable the package's notifications
1229 getOwner().setNotificationsEnabled(false);
1232 .setNegativeButton(R.string.dlg_cancel,
1233 new DialogInterface.OnClickListener() {
1234 public void onClick(DialogInterface dialog, int which) {
1235 // Re-enable the checkbox
1236 getOwner().mNotificationSwitch.setChecked(true);
1240 case DLG_SPECIAL_DISABLE:
1241 return new AlertDialog.Builder(getActivity())
1242 .setTitle(getActivity().getText(R.string.app_special_disable_dlg_title))
1243 .setMessage(getActivity().getText(R.string.app_special_disable_dlg_text))
1244 .setPositiveButton(R.string.dlg_ok,
1245 new DialogInterface.OnClickListener() {
1246 public void onClick(DialogInterface dialog, int which) {
1247 // Clear user data here
1248 getOwner().uninstallPkg(getOwner().mAppEntry.info.packageName,
1252 .setNegativeButton(R.string.dlg_cancel, null)
1255 throw new IllegalArgumentException("unknown id " + id);
1259 private void uninstallPkg(String packageName, boolean allUsers, boolean andDisable) {
1260 // Create new intent to launch Uninstaller activity
1261 Uri packageURI = Uri.parse("package:"+packageName);
1262 Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageURI);
1263 uninstallIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, allUsers);
1264 startActivityForResult(uninstallIntent, REQUEST_UNINSTALL);
1265 mDisableAfterUninstall = andDisable;
1268 private void forceStopPackage(String pkgName) {
1269 ActivityManager am = (ActivityManager)getActivity().getSystemService(
1270 Context.ACTIVITY_SERVICE);
1271 am.forceStopPackage(pkgName);
1272 mState.invalidatePackage(pkgName);
1273 ApplicationsState.AppEntry newEnt = mState.getEntry(pkgName);
1274 if (newEnt != null) {
1280 private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() {
1282 public void onReceive(Context context, Intent intent) {
1283 updateForceStopButton(getResultCode() != Activity.RESULT_CANCELED);
1287 private void updateForceStopButton(boolean enabled) {
1288 if (mAppControlRestricted) {
1289 mForceStopButton.setEnabled(false);
1291 mForceStopButton.setEnabled(enabled);
1292 mForceStopButton.setOnClickListener(InstalledAppDetails.this);
1296 private void checkForceStop() {
1297 if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
1298 // User can't force stop device admin.
1299 updateForceStopButton(false);
1300 } else if ((mAppEntry.info.flags&ApplicationInfo.FLAG_STOPPED) == 0) {
1301 // If the app isn't explicitly stopped, then always show the
1302 // force stop button.
1303 updateForceStopButton(true);
1305 Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART,
1306 Uri.fromParts("package", mAppEntry.info.packageName, null));
1307 intent.putExtra(Intent.EXTRA_PACKAGES, new String[] { mAppEntry.info.packageName });
1308 intent.putExtra(Intent.EXTRA_UID, mAppEntry.info.uid);
1309 intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(mAppEntry.info.uid));
1310 getActivity().sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
1311 mCheckKillProcessesReceiver, null, Activity.RESULT_CANCELED, null, null);
1315 static class DisableChanger extends AsyncTask<Object, Object, Object> {
1316 final PackageManager mPm;
1317 final WeakReference<InstalledAppDetails> mActivity;
1318 final ApplicationInfo mInfo;
1321 DisableChanger(InstalledAppDetails activity, ApplicationInfo info, int state) {
1323 mActivity = new WeakReference<InstalledAppDetails>(activity);
1329 protected Object doInBackground(Object... params) {
1330 mPm.setApplicationEnabledSetting(mInfo.packageName, mState, 0);
1335 private void setNotificationsEnabled(boolean enabled) {
1336 String packageName = mAppEntry.info.packageName;
1337 INotificationManager nm = INotificationManager.Stub.asInterface(
1338 ServiceManager.getService(Context.NOTIFICATION_SERVICE));
1340 final boolean enable = mNotificationSwitch.isChecked();
1341 nm.setNotificationsEnabledForPackage(packageName, mAppEntry.info.uid, enabled);
1342 } catch (android.os.RemoteException ex) {
1343 mNotificationSwitch.setChecked(!enabled); // revert
1347 private int getPremiumSmsPermission(String packageName) {
1349 if (mSmsManager != null) {
1350 return mSmsManager.getPremiumSmsPermission(packageName);
1352 } catch (RemoteException ex) {
1355 return SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN;
1359 * Method implementing functionality of buttons clicked
1360 * @see android.view.View.OnClickListener#onClick(android.view.View)
1362 public void onClick(View v) {
1363 String packageName = mAppEntry.info.packageName;
1364 if(v == mUninstallButton) {
1365 if (mUpdatedSysApp) {
1366 showDialogInner(DLG_FACTORY_RESET, 0);
1368 if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
1369 if (mAppEntry.info.enabled) {
1370 showDialogInner(DLG_DISABLE, 0);
1372 new DisableChanger(this, mAppEntry.info,
1373 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT)
1374 .execute((Object)null);
1376 } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_INSTALLED) == 0) {
1377 uninstallPkg(packageName, true, false);
1379 uninstallPkg(packageName, false, false);
1382 } else if(v == mSpecialDisableButton) {
1383 showDialogInner(DLG_SPECIAL_DISABLE, 0);
1384 } else if(v == mActivitiesButton) {
1385 if (mUsbManager != null) {
1386 mPm.clearPackagePreferredActivities(packageName);
1388 mUsbManager.clearDefaults(packageName, UserHandle.myUserId());
1389 } catch (RemoteException e) {
1390 Log.e(TAG, "mUsbManager.clearDefaults", e);
1392 mAppWidgetManager.setBindAppWidgetPermission(packageName, false);
1393 TextView autoLaunchTitleView =
1394 (TextView) mRootView.findViewById(R.id.auto_launch_title);
1395 TextView autoLaunchView = (TextView) mRootView.findViewById(R.id.auto_launch);
1396 resetLaunchDefaultsUi(autoLaunchTitleView, autoLaunchView);
1398 } else if(v == mClearDataButton) {
1399 if (mAppEntry.info.manageSpaceActivityName != null) {
1400 if (!Utils.isMonkeyRunning()) {
1401 Intent intent = new Intent(Intent.ACTION_DEFAULT);
1402 intent.setClassName(mAppEntry.info.packageName,
1403 mAppEntry.info.manageSpaceActivityName);
1404 startActivityForResult(intent, REQUEST_MANAGE_SPACE);
1407 showDialogInner(DLG_CLEAR_DATA, 0);
1409 } else if (v == mClearCacheButton) {
1410 // Lazy initialization of observer
1411 if (mClearCacheObserver == null) {
1412 mClearCacheObserver = new ClearCacheObserver();
1414 mPm.deleteApplicationCacheFiles(packageName, mClearCacheObserver);
1415 } else if (v == mForceStopButton) {
1416 showDialogInner(DLG_FORCE_STOP, 0);
1417 //forceStopPackage(mAppInfo.packageName);
1418 } else if (v == mMoveAppButton) {
1419 if (mPackageMoveObserver == null) {
1420 mPackageMoveObserver = new PackageMoveObserver();
1422 int moveFlags = (mAppEntry.info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0 ?
1423 PackageManager.MOVE_INTERNAL : PackageManager.MOVE_EXTERNAL_MEDIA;
1424 mMoveInProgress = true;
1426 mPm.movePackage(mAppEntry.info.packageName, mPackageMoveObserver, moveFlags);
1431 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
1432 String packageName = mAppEntry.info.packageName;
1433 ActivityManager am = (ActivityManager)
1434 getActivity().getSystemService(Context.ACTIVITY_SERVICE);
1435 if (buttonView == mAskCompatibilityCB) {
1436 am.setPackageAskScreenCompat(packageName, isChecked);
1437 } else if (buttonView == mEnableCompatibilityCB) {
1438 am.setPackageScreenCompatMode(packageName, isChecked ?
1439 ActivityManager.COMPAT_MODE_ENABLED : ActivityManager.COMPAT_MODE_DISABLED);
1440 } else if (buttonView == mNotificationSwitch) {
1442 showDialogInner(DLG_DISABLE_NOTIFICATIONS, 0);
1444 setNotificationsEnabled(true);