InstalledAppDetails.java revision 2715376cfa4d220f183623a5f35214d1bd537376
1/** 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy 6 * of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations 14 * under the License. 15 */ 16 17package com.android.settings.applications; 18 19import com.android.settings.R; 20import com.android.settings.applications.ApplicationsState.AppEntry; 21 22import android.app.Activity; 23import android.app.ActivityManager; 24import android.app.AlertDialog; 25import android.app.Dialog; 26import android.app.DialogFragment; 27import android.app.Fragment; 28import android.content.BroadcastReceiver; 29import android.content.Context; 30import android.content.DialogInterface; 31import android.content.Intent; 32import android.content.IntentFilter; 33import android.content.pm.ApplicationInfo; 34import android.content.pm.IPackageDataObserver; 35import android.content.pm.IPackageMoveObserver; 36import android.content.pm.PackageInfo; 37import android.content.pm.PackageManager; 38import android.content.pm.ResolveInfo; 39import android.content.pm.PackageManager.NameNotFoundException; 40import android.hardware.usb.IUsbManager; 41import android.net.Uri; 42import android.os.AsyncTask; 43import android.os.Bundle; 44import android.os.Environment; 45import android.os.Handler; 46import android.os.IBinder; 47import android.os.Message; 48import android.os.RemoteException; 49import android.os.ServiceManager; 50import android.preference.PreferenceActivity; 51import android.text.format.Formatter; 52import android.util.Log; 53 54import java.lang.ref.WeakReference; 55import java.util.ArrayList; 56import java.util.List; 57import android.content.ComponentName; 58import android.view.LayoutInflater; 59import android.view.View; 60import android.view.ViewGroup; 61import android.widget.AppSecurityPermissions; 62import android.widget.Button; 63import android.widget.ImageView; 64import android.widget.LinearLayout; 65import android.widget.TextView; 66 67/** 68 * Activity to display application information from Settings. This activity presents 69 * extended information associated with a package like code, data, total size, permissions 70 * used by the application and also the set of default launchable activities. 71 * For system applications, an option to clear user data is displayed only if data size is > 0. 72 * System applications that do not want clear user data do not have this option. 73 * For non-system applications, there is no option to clear data. Instead there is an option to 74 * uninstall the application. 75 */ 76public class InstalledAppDetails extends Fragment 77 implements View.OnClickListener, ApplicationsState.Callbacks { 78 private static final String TAG="InstalledAppDetails"; 79 static final boolean SUPPORT_DISABLE_APPS = false; 80 private static final boolean localLOGV = false; 81 82 public static final String ARG_PACKAGE_NAME = "package"; 83 84 private PackageManager mPm; 85 private IUsbManager mUsbManager; 86 private ApplicationsState mState; 87 private ApplicationsState.AppEntry mAppEntry; 88 private PackageInfo mPackageInfo; 89 private CanBeOnSdCardChecker mCanBeOnSdCardChecker; 90 private View mRootView; 91 private Button mUninstallButton; 92 private boolean mMoveInProgress = false; 93 private boolean mUpdatedSysApp = false; 94 private Button mActivitiesButton; 95 private boolean mCanClearData = true; 96 private TextView mAppVersion; 97 private TextView mTotalSize; 98 private TextView mAppSize; 99 private TextView mDataSize; 100 private TextView mExternalSize; 101 private ClearUserDataObserver mClearDataObserver; 102 // Views related to cache info 103 private TextView mCacheSize; 104 private Button mClearCacheButton; 105 private ClearCacheObserver mClearCacheObserver; 106 private Button mForceStopButton; 107 private Button mClearDataButton; 108 private Button mMoveAppButton; 109 110 private PackageMoveObserver mPackageMoveObserver; 111 112 private boolean mHaveSizes = false; 113 private long mLastCodeSize = -1; 114 private long mLastDataSize = -1; 115 private long mLastExternalSize = -1; 116 private long mLastCacheSize = -1; 117 private long mLastTotalSize = -1; 118 119 //internal constants used in Handler 120 private static final int OP_SUCCESSFUL = 1; 121 private static final int OP_FAILED = 2; 122 private static final int CLEAR_USER_DATA = 1; 123 private static final int CLEAR_CACHE = 3; 124 private static final int PACKAGE_MOVE = 4; 125 126 // invalid size value used initially and also when size retrieval through PackageManager 127 // fails for whatever reason 128 private static final int SIZE_INVALID = -1; 129 130 // Resource strings 131 private CharSequence mInvalidSizeStr; 132 private CharSequence mComputingStr; 133 134 // Dialog identifiers used in showDialog 135 private static final int DLG_BASE = 0; 136 private static final int DLG_CLEAR_DATA = DLG_BASE + 1; 137 private static final int DLG_FACTORY_RESET = DLG_BASE + 2; 138 private static final int DLG_APP_NOT_FOUND = DLG_BASE + 3; 139 private static final int DLG_CANNOT_CLEAR_DATA = DLG_BASE + 4; 140 private static final int DLG_FORCE_STOP = DLG_BASE + 5; 141 private static final int DLG_MOVE_FAILED = DLG_BASE + 6; 142 143 private Handler mHandler = new Handler() { 144 public void handleMessage(Message msg) { 145 // If the fragment is gone, don't process any more messages. 146 if (getView() == null) { 147 return; 148 } 149 switch (msg.what) { 150 case CLEAR_USER_DATA: 151 processClearMsg(msg); 152 break; 153 case CLEAR_CACHE: 154 // Refresh size info 155 mState.requestSize(mAppEntry.info.packageName); 156 break; 157 case PACKAGE_MOVE: 158 processMoveMsg(msg); 159 break; 160 default: 161 break; 162 } 163 } 164 }; 165 166 class ClearUserDataObserver extends IPackageDataObserver.Stub { 167 public void onRemoveCompleted(final String packageName, final boolean succeeded) { 168 final Message msg = mHandler.obtainMessage(CLEAR_USER_DATA); 169 msg.arg1 = succeeded?OP_SUCCESSFUL:OP_FAILED; 170 mHandler.sendMessage(msg); 171 } 172 } 173 174 class ClearCacheObserver extends IPackageDataObserver.Stub { 175 public void onRemoveCompleted(final String packageName, final boolean succeeded) { 176 final Message msg = mHandler.obtainMessage(CLEAR_CACHE); 177 msg.arg1 = succeeded ? OP_SUCCESSFUL:OP_FAILED; 178 mHandler.sendMessage(msg); 179 } 180 } 181 182 class PackageMoveObserver extends IPackageMoveObserver.Stub { 183 public void packageMoved(String packageName, int returnCode) throws RemoteException { 184 final Message msg = mHandler.obtainMessage(PACKAGE_MOVE); 185 msg.arg1 = returnCode; 186 mHandler.sendMessage(msg); 187 } 188 } 189 190 private String getSizeStr(long size) { 191 if (size == SIZE_INVALID) { 192 return mInvalidSizeStr.toString(); 193 } 194 return Formatter.formatFileSize(getActivity(), size); 195 } 196 197 private void initDataButtons() { 198 if ((mAppEntry.info.flags&(ApplicationInfo.FLAG_SYSTEM 199 | ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA)) 200 == ApplicationInfo.FLAG_SYSTEM) { 201 mClearDataButton.setText(R.string.clear_user_data_text); 202 mClearDataButton.setEnabled(false); 203 mCanClearData = false; 204 } else { 205 if (mAppEntry.info.manageSpaceActivityName != null) { 206 mClearDataButton.setText(R.string.manage_space_text); 207 } else { 208 mClearDataButton.setText(R.string.clear_user_data_text); 209 } 210 mClearDataButton.setOnClickListener(this); 211 } 212 } 213 214 private CharSequence getMoveErrMsg(int errCode) { 215 switch (errCode) { 216 case PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE: 217 return getActivity().getString(R.string.insufficient_storage); 218 case PackageManager.MOVE_FAILED_DOESNT_EXIST: 219 return getActivity().getString(R.string.does_not_exist); 220 case PackageManager.MOVE_FAILED_FORWARD_LOCKED: 221 return getActivity().getString(R.string.app_forward_locked); 222 case PackageManager.MOVE_FAILED_INVALID_LOCATION: 223 return getActivity().getString(R.string.invalid_location); 224 case PackageManager.MOVE_FAILED_SYSTEM_PACKAGE: 225 return getActivity().getString(R.string.system_package); 226 case PackageManager.MOVE_FAILED_INTERNAL_ERROR: 227 return ""; 228 } 229 return ""; 230 } 231 232 private void initMoveButton() { 233 if (Environment.isExternalStorageEmulated()) { 234 mMoveAppButton.setVisibility(View.INVISIBLE); 235 return; 236 } 237 boolean dataOnly = false; 238 dataOnly = (mPackageInfo == null) && (mAppEntry != null); 239 boolean moveDisable = true; 240 if (dataOnly) { 241 mMoveAppButton.setText(R.string.move_app); 242 } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) { 243 mMoveAppButton.setText(R.string.move_app_to_internal); 244 // Always let apps move to internal storage from sdcard. 245 moveDisable = false; 246 } else { 247 mMoveAppButton.setText(R.string.move_app_to_sdcard); 248 mCanBeOnSdCardChecker.init(); 249 moveDisable = !mCanBeOnSdCardChecker.check(mAppEntry.info); 250 } 251 if (moveDisable) { 252 mMoveAppButton.setEnabled(false); 253 } else { 254 mMoveAppButton.setOnClickListener(this); 255 mMoveAppButton.setEnabled(true); 256 } 257 } 258 259 private void initUninstallButtons() { 260 mUpdatedSysApp = (mAppEntry.info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; 261 boolean enabled = true; 262 if (mUpdatedSysApp) { 263 mUninstallButton.setText(R.string.app_factory_reset); 264 } else { 265 if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 266 enabled = false; 267 if (SUPPORT_DISABLE_APPS) { 268 try { 269 // Try to prevent the user from bricking their phone 270 // by not allowing disabling of apps signed with the 271 // system cert and any launcher app in the system. 272 PackageInfo sys = mPm.getPackageInfo("android", 273 PackageManager.GET_SIGNATURES); 274 Intent intent = new Intent(Intent.ACTION_MAIN); 275 intent.addCategory(Intent.CATEGORY_HOME); 276 intent.setPackage(mAppEntry.info.packageName); 277 List<ResolveInfo> homes = mPm.queryIntentActivities(intent, 0); 278 if ((homes != null && homes.size() > 0) || 279 (mPackageInfo != null && 280 sys.signatures[0].equals(mPackageInfo.signatures[0]))) { 281 // Disable button for core system applications. 282 mUninstallButton.setText(R.string.disable_text); 283 } else if (mAppEntry.info.enabled) { 284 mUninstallButton.setText(R.string.disable_text); 285 enabled = true; 286 } else { 287 mUninstallButton.setText(R.string.enable_text); 288 enabled = true; 289 } 290 } catch (PackageManager.NameNotFoundException e) { 291 Log.w(TAG, "Unable to get package info", e); 292 } 293 } 294 } else { 295 mUninstallButton.setText(R.string.uninstall_text); 296 } 297 } 298 mUninstallButton.setEnabled(enabled); 299 if (enabled) { 300 // Register listener 301 mUninstallButton.setOnClickListener(this); 302 } 303 } 304 305 /** Called when the activity is first created. */ 306 @Override 307 public void onCreate(Bundle icicle) { 308 super.onCreate(icicle); 309 310 mState = ApplicationsState.getInstance(getActivity().getApplication()); 311 mPm = getActivity().getPackageManager(); 312 IBinder b = ServiceManager.getService(Context.USB_SERVICE); 313 mUsbManager = IUsbManager.Stub.asInterface(b); 314 315 mCanBeOnSdCardChecker = new CanBeOnSdCardChecker(); 316 } 317 318 @Override 319 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 320 View view = mRootView = inflater.inflate(R.layout.installed_app_details, null); 321 322 mComputingStr = getActivity().getText(R.string.computing_size); 323 324 // Set default values on sizes 325 mTotalSize = (TextView)view.findViewById(R.id.total_size_text); 326 mAppSize = (TextView)view.findViewById(R.id.application_size_text); 327 mDataSize = (TextView)view.findViewById(R.id.data_size_text); 328 mExternalSize = (TextView)view.findViewById(R.id.external_size_text); 329 330 // Get Control button panel 331 View btnPanel = view.findViewById(R.id.control_buttons_panel); 332 mForceStopButton = (Button) btnPanel.findViewById(R.id.left_button); 333 mForceStopButton.setText(R.string.force_stop); 334 mUninstallButton = (Button)btnPanel.findViewById(R.id.right_button); 335 mForceStopButton.setEnabled(false); 336 337 // Initialize clear data and move install location buttons 338 View data_buttons_panel = view.findViewById(R.id.data_buttons_panel); 339 mClearDataButton = (Button) data_buttons_panel.findViewById(R.id.left_button); 340 mMoveAppButton = (Button) data_buttons_panel.findViewById(R.id.right_button); 341 342 // Cache section 343 mCacheSize = (TextView) view.findViewById(R.id.cache_size_text); 344 mClearCacheButton = (Button) view.findViewById(R.id.clear_cache_button); 345 346 mActivitiesButton = (Button)view.findViewById(R.id.clear_activities_button); 347 348 return view; 349 } 350 351 // Utility method to set applicaiton label and icon. 352 private void setAppLabelAndIcon(PackageInfo pkgInfo) { 353 View appSnippet = mRootView.findViewById(R.id.app_snippet); 354 ImageView icon = (ImageView) appSnippet.findViewById(R.id.app_icon); 355 mState.ensureIcon(mAppEntry); 356 icon.setImageDrawable(mAppEntry.icon); 357 // Set application name. 358 TextView label = (TextView) appSnippet.findViewById(R.id.app_name); 359 label.setText(mAppEntry.label); 360 // Version number of application 361 mAppVersion = (TextView) appSnippet.findViewById(R.id.app_size); 362 363 if (pkgInfo != null && pkgInfo.versionName != null) { 364 mAppVersion.setVisibility(View.VISIBLE); 365 mAppVersion.setText(getActivity().getString(R.string.version_text, 366 String.valueOf(pkgInfo.versionName))); 367 } else { 368 mAppVersion.setVisibility(View.INVISIBLE); 369 } 370 } 371 372 @Override 373 public void onResume() { 374 super.onResume(); 375 376 mState.resume(this); 377 if (!refreshUi()) { 378 setIntentAndFinish(true, true); 379 } 380 } 381 382 @Override 383 public void onPause() { 384 super.onPause(); 385 mState.pause(); 386 } 387 388 @Override 389 public void onAllSizesComputed() { 390 } 391 392 @Override 393 public void onPackageIconChanged() { 394 } 395 396 @Override 397 public void onPackageListChanged() { 398 refreshUi(); 399 } 400 401 @Override 402 public void onRebuildComplete(ArrayList<AppEntry> apps) { 403 } 404 405 @Override 406 public void onPackageSizeChanged(String packageName) { 407 if (packageName.equals(mAppEntry.info.packageName)) { 408 refreshSizeInfo(); 409 } 410 } 411 412 @Override 413 public void onRunningStateChanged(boolean running) { 414 } 415 416 private boolean refreshUi() { 417 if (mMoveInProgress) { 418 return true; 419 } 420 final Bundle args = getArguments(); 421 String packageName = (args != null) ? args.getString(ARG_PACKAGE_NAME) : null; 422 if (packageName == null) { 423 Intent intent = (args == null) ? 424 getActivity().getIntent() : (Intent) args.getParcelable("intent"); 425 if (intent != null) { 426 packageName = intent.getData().getSchemeSpecificPart(); 427 } 428 } 429 mAppEntry = mState.getEntry(packageName); 430 431 if (mAppEntry == null) { 432 return false; // onCreate must have failed, make sure to exit 433 } 434 435 // Get application info again to refresh changed properties of application 436 try { 437 mPackageInfo = mPm.getPackageInfo(mAppEntry.info.packageName, 438 PackageManager.GET_DISABLED_COMPONENTS | 439 PackageManager.GET_UNINSTALLED_PACKAGES | 440 PackageManager.GET_SIGNATURES); 441 } catch (NameNotFoundException e) { 442 Log.e(TAG, "Exception when retrieving package:" + mAppEntry.info.packageName, e); 443 return false; // onCreate must have failed, make sure to exit 444 } 445 446 // Get list of preferred activities 447 List<ComponentName> prefActList = new ArrayList<ComponentName>(); 448 449 // Intent list cannot be null. so pass empty list 450 List<IntentFilter> intentList = new ArrayList<IntentFilter>(); 451 mPm.getPreferredActivities(intentList, prefActList, packageName); 452 if(localLOGV) Log.i(TAG, "Have "+prefActList.size()+" number of activities in prefered list"); 453 boolean hasUsbDefaults = false; 454 try { 455 hasUsbDefaults = mUsbManager.hasDefaults(packageName); 456 } catch (RemoteException e) { 457 Log.e(TAG, "mUsbManager.hasDefaults", e); 458 } 459 TextView autoLaunchView = (TextView)mRootView.findViewById(R.id.auto_launch); 460 if (prefActList.size() <= 0 && !hasUsbDefaults) { 461 // Disable clear activities button 462 autoLaunchView.setText(R.string.auto_launch_disable_text); 463 mActivitiesButton.setEnabled(false); 464 } else { 465 autoLaunchView.setText(R.string.auto_launch_enable_text); 466 mActivitiesButton.setEnabled(true); 467 mActivitiesButton.setOnClickListener(this); 468 } 469 470 // Security permissions section 471 LinearLayout permsView = (LinearLayout) mRootView.findViewById(R.id.permissions_section); 472 AppSecurityPermissions asp = new AppSecurityPermissions(getActivity(), packageName); 473 if (asp.getPermissionCount() > 0) { 474 permsView.setVisibility(View.VISIBLE); 475 // Make the security sections header visible 476 LinearLayout securityList = (LinearLayout) permsView.findViewById( 477 R.id.security_settings_list); 478 securityList.removeAllViews(); 479 securityList.addView(asp.getPermissionsView()); 480 } else { 481 permsView.setVisibility(View.GONE); 482 } 483 484 checkForceStop(); 485 setAppLabelAndIcon(mPackageInfo); 486 refreshButtons(); 487 refreshSizeInfo(); 488 return true; 489 } 490 491 private void setIntentAndFinish(boolean finish, boolean appChanged) { 492 if(localLOGV) Log.i(TAG, "appChanged="+appChanged); 493 Intent intent = new Intent(); 494 intent.putExtra(ManageApplications.APP_CHG, appChanged); 495 PreferenceActivity pa = (PreferenceActivity)getActivity(); 496 pa.finishPreferencePanel(this, Activity.RESULT_OK, intent); 497 } 498 499 private void refreshSizeInfo() { 500 if (mAppEntry.size == ApplicationsState.SIZE_INVALID 501 || mAppEntry.size == ApplicationsState.SIZE_UNKNOWN) { 502 mLastCodeSize = mLastDataSize = mLastCacheSize = mLastTotalSize = -1; 503 if (!mHaveSizes) { 504 mAppSize.setText(mComputingStr); 505 mDataSize.setText(mComputingStr); 506 mCacheSize.setText(mComputingStr); 507 mTotalSize.setText(mComputingStr); 508 } 509 mClearDataButton.setEnabled(false); 510 mClearCacheButton.setEnabled(false); 511 512 } else { 513 mHaveSizes = true; 514 if (mLastCodeSize != mAppEntry.codeSize) { 515 mLastCodeSize = mAppEntry.codeSize; 516 mAppSize.setText(getSizeStr(mAppEntry.codeSize)); 517 } 518 if (mLastDataSize != mAppEntry.dataSize) { 519 mLastDataSize = mAppEntry.dataSize; 520 mDataSize.setText(getSizeStr(mAppEntry.dataSize)); 521 } 522 if (mLastExternalSize != mAppEntry.externalSize) { 523 mLastExternalSize = mAppEntry.externalSize; 524 mExternalSize.setText(getSizeStr(mAppEntry.externalSize)); 525 } 526 if (mLastCacheSize != mAppEntry.cacheSize) { 527 mLastCacheSize = mAppEntry.cacheSize; 528 mCacheSize.setText(getSizeStr(mAppEntry.cacheSize)); 529 } 530 if (mLastTotalSize != mAppEntry.size) { 531 mLastTotalSize = mAppEntry.size; 532 mTotalSize.setText(getSizeStr(mAppEntry.size)); 533 } 534 535 if (mAppEntry.dataSize <= 0 || !mCanClearData) { 536 mClearDataButton.setEnabled(false); 537 } else { 538 mClearDataButton.setEnabled(true); 539 mClearDataButton.setOnClickListener(this); 540 } 541 if (mAppEntry.cacheSize <= 0) { 542 mClearCacheButton.setEnabled(false); 543 } else { 544 mClearCacheButton.setEnabled(true); 545 mClearCacheButton.setOnClickListener(this); 546 } 547 } 548 } 549 550 /* 551 * Private method to handle clear message notification from observer when 552 * the async operation from PackageManager is complete 553 */ 554 private void processClearMsg(Message msg) { 555 int result = msg.arg1; 556 String packageName = mAppEntry.info.packageName; 557 mClearDataButton.setText(R.string.clear_user_data_text); 558 if(result == OP_SUCCESSFUL) { 559 Log.i(TAG, "Cleared user data for package : "+packageName); 560 mState.requestSize(mAppEntry.info.packageName); 561 } else { 562 mClearDataButton.setEnabled(true); 563 } 564 checkForceStop(); 565 } 566 567 private void refreshButtons() { 568 if (!mMoveInProgress) { 569 initUninstallButtons(); 570 initDataButtons(); 571 initMoveButton(); 572 } else { 573 mMoveAppButton.setText(R.string.moving); 574 mMoveAppButton.setEnabled(false); 575 mUninstallButton.setEnabled(false); 576 } 577 } 578 579 private void processMoveMsg(Message msg) { 580 int result = msg.arg1; 581 String packageName = mAppEntry.info.packageName; 582 // Refresh the button attributes. 583 mMoveInProgress = false; 584 if (result == PackageManager.MOVE_SUCCEEDED) { 585 Log.i(TAG, "Moved resources for " + packageName); 586 // Refresh size information again. 587 mState.requestSize(mAppEntry.info.packageName); 588 } else { 589 showDialogInner(DLG_MOVE_FAILED, result); 590 } 591 refreshUi(); 592 } 593 594 /* 595 * Private method to initiate clearing user data when the user clicks the clear data 596 * button for a system package 597 */ 598 private void initiateClearUserData() { 599 mClearDataButton.setEnabled(false); 600 // Invoke uninstall or clear user data based on sysPackage 601 String packageName = mAppEntry.info.packageName; 602 Log.i(TAG, "Clearing user data for package : " + packageName); 603 if (mClearDataObserver == null) { 604 mClearDataObserver = new ClearUserDataObserver(); 605 } 606 ActivityManager am = (ActivityManager) 607 getActivity().getSystemService(Context.ACTIVITY_SERVICE); 608 boolean res = am.clearApplicationUserData(packageName, mClearDataObserver); 609 if (!res) { 610 // Clearing data failed for some obscure reason. Just log error for now 611 Log.i(TAG, "Couldnt clear application user data for package:"+packageName); 612 showDialogInner(DLG_CANNOT_CLEAR_DATA, 0); 613 } else { 614 mClearDataButton.setText(R.string.recompute_size); 615 } 616 } 617 618 private void showDialogInner(int id, int moveErrorCode) { 619 DialogFragment newFragment = MyAlertDialogFragment.newInstance(id, moveErrorCode); 620 newFragment.setTargetFragment(this, 0); 621 newFragment.show(getFragmentManager(), "dialog " + id); 622 } 623 624 public static class MyAlertDialogFragment extends DialogFragment { 625 626 public static MyAlertDialogFragment newInstance(int id, int moveErrorCode) { 627 MyAlertDialogFragment frag = new MyAlertDialogFragment(); 628 Bundle args = new Bundle(); 629 args.putInt("id", id); 630 args.putInt("moveError", moveErrorCode); 631 frag.setArguments(args); 632 return frag; 633 } 634 635 InstalledAppDetails getOwner() { 636 return (InstalledAppDetails)getTargetFragment(); 637 } 638 639 @Override 640 public Dialog onCreateDialog(Bundle savedInstanceState) { 641 int id = getArguments().getInt("id"); 642 int moveErrorCode = getArguments().getInt("moveError"); 643 switch (id) { 644 case DLG_CLEAR_DATA: 645 return new AlertDialog.Builder(getActivity()) 646 .setTitle(getActivity().getText(R.string.clear_data_dlg_title)) 647 .setIcon(android.R.drawable.ic_dialog_alert) 648 .setMessage(getActivity().getText(R.string.clear_data_dlg_text)) 649 .setPositiveButton(R.string.dlg_ok, 650 new DialogInterface.OnClickListener() { 651 public void onClick(DialogInterface dialog, int which) { 652 // Clear user data here 653 getOwner().initiateClearUserData(); 654 } 655 }) 656 .setNegativeButton(R.string.dlg_cancel, null) 657 .create(); 658 case DLG_FACTORY_RESET: 659 return new AlertDialog.Builder(getActivity()) 660 .setTitle(getActivity().getText(R.string.app_factory_reset_dlg_title)) 661 .setIcon(android.R.drawable.ic_dialog_alert) 662 .setMessage(getActivity().getText(R.string.app_factory_reset_dlg_text)) 663 .setPositiveButton(R.string.dlg_ok, 664 new DialogInterface.OnClickListener() { 665 public void onClick(DialogInterface dialog, int which) { 666 // Clear user data here 667 getOwner().uninstallPkg(getOwner().mAppEntry.info.packageName); 668 } 669 }) 670 .setNegativeButton(R.string.dlg_cancel, null) 671 .create(); 672 case DLG_APP_NOT_FOUND: 673 return new AlertDialog.Builder(getActivity()) 674 .setTitle(getActivity().getText(R.string.app_not_found_dlg_title)) 675 .setIcon(android.R.drawable.ic_dialog_alert) 676 .setMessage(getActivity().getText(R.string.app_not_found_dlg_title)) 677 .setNeutralButton(getActivity().getText(R.string.dlg_ok), 678 new DialogInterface.OnClickListener() { 679 public void onClick(DialogInterface dialog, int which) { 680 //force to recompute changed value 681 getOwner().setIntentAndFinish(true, true); 682 } 683 }) 684 .create(); 685 case DLG_CANNOT_CLEAR_DATA: 686 return new AlertDialog.Builder(getActivity()) 687 .setTitle(getActivity().getText(R.string.clear_failed_dlg_title)) 688 .setIcon(android.R.drawable.ic_dialog_alert) 689 .setMessage(getActivity().getText(R.string.clear_failed_dlg_text)) 690 .setNeutralButton(R.string.dlg_ok, 691 new DialogInterface.OnClickListener() { 692 public void onClick(DialogInterface dialog, int which) { 693 getOwner().mClearDataButton.setEnabled(false); 694 //force to recompute changed value 695 getOwner().setIntentAndFinish(false, false); 696 } 697 }) 698 .create(); 699 case DLG_FORCE_STOP: 700 return new AlertDialog.Builder(getActivity()) 701 .setTitle(getActivity().getText(R.string.force_stop_dlg_title)) 702 .setIcon(android.R.drawable.ic_dialog_alert) 703 .setMessage(getActivity().getText(R.string.force_stop_dlg_text)) 704 .setPositiveButton(R.string.dlg_ok, 705 new DialogInterface.OnClickListener() { 706 public void onClick(DialogInterface dialog, int which) { 707 // Force stop 708 getOwner().forceStopPackage(getOwner().mAppEntry.info.packageName); 709 } 710 }) 711 .setNegativeButton(R.string.dlg_cancel, null) 712 .create(); 713 case DLG_MOVE_FAILED: 714 CharSequence msg = getActivity().getString(R.string.move_app_failed_dlg_text, 715 getOwner().getMoveErrMsg(moveErrorCode)); 716 return new AlertDialog.Builder(getActivity()) 717 .setTitle(getActivity().getText(R.string.move_app_failed_dlg_title)) 718 .setIcon(android.R.drawable.ic_dialog_alert) 719 .setMessage(msg) 720 .setNeutralButton(R.string.dlg_ok, null) 721 .create(); 722 } 723 throw new IllegalArgumentException("unknown id " + id); 724 } 725 } 726 727 private void uninstallPkg(String packageName) { 728 // Create new intent to launch Uninstaller activity 729 Uri packageURI = Uri.parse("package:"+packageName); 730 Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI); 731 startActivity(uninstallIntent); 732 setIntentAndFinish(true, true); 733 } 734 735 private void forceStopPackage(String pkgName) { 736 ActivityManager am = (ActivityManager)getActivity().getSystemService( 737 Context.ACTIVITY_SERVICE); 738 am.forceStopPackage(pkgName); 739 mState.invalidatePackage(pkgName); 740 ApplicationsState.AppEntry newEnt = mState.getEntry(pkgName); 741 if (newEnt != null) { 742 mAppEntry = newEnt; 743 } 744 checkForceStop(); 745 } 746 747 private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() { 748 @Override 749 public void onReceive(Context context, Intent intent) { 750 updateForceStopButton(getResultCode() != Activity.RESULT_CANCELED); 751 } 752 }; 753 754 private void updateForceStopButton(boolean enabled) { 755 mForceStopButton.setEnabled(enabled); 756 mForceStopButton.setOnClickListener(InstalledAppDetails.this); 757 } 758 759 private void checkForceStop() { 760 Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART, 761 Uri.fromParts("package", mAppEntry.info.packageName, null)); 762 intent.putExtra(Intent.EXTRA_PACKAGES, new String[] { mAppEntry.info.packageName }); 763 intent.putExtra(Intent.EXTRA_UID, mAppEntry.info.uid); 764 if ((mAppEntry.info.flags&ApplicationInfo.FLAG_STOPPED) == 0) { 765 // If the app isn't explicitly stopped, then always show the 766 // force stop button. 767 updateForceStopButton(true); 768 } else { 769 getActivity().sendOrderedBroadcast(intent, null, mCheckKillProcessesReceiver, null, 770 Activity.RESULT_CANCELED, null, null); 771 } 772 } 773 774 static class DisableChanger extends AsyncTask<Object, Object, Object> { 775 final PackageManager mPm; 776 final WeakReference<InstalledAppDetails> mActivity; 777 final ApplicationInfo mInfo; 778 final int mState; 779 780 DisableChanger(InstalledAppDetails activity, ApplicationInfo info, int state) { 781 mPm = activity.mPm; 782 mActivity = new WeakReference<InstalledAppDetails>(activity); 783 mInfo = info; 784 mState = state; 785 } 786 787 @Override 788 protected Object doInBackground(Object... params) { 789 mPm.setApplicationEnabledSetting(mInfo.packageName, mState, 0); 790 return null; 791 } 792 } 793 794 /* 795 * Method implementing functionality of buttons clicked 796 * @see android.view.View.OnClickListener#onClick(android.view.View) 797 */ 798 public void onClick(View v) { 799 String packageName = mAppEntry.info.packageName; 800 if(v == mUninstallButton) { 801 if (mUpdatedSysApp) { 802 showDialogInner(DLG_FACTORY_RESET, 0); 803 } else { 804 if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 805 new DisableChanger(this, mAppEntry.info, mAppEntry.info.enabled ? 806 PackageManager.COMPONENT_ENABLED_STATE_DISABLED 807 : PackageManager.COMPONENT_ENABLED_STATE_DEFAULT).execute((Object)null); 808 } else { 809 uninstallPkg(packageName); 810 } 811 } 812 } else if(v == mActivitiesButton) { 813 mPm.clearPackagePreferredActivities(packageName); 814 try { 815 mUsbManager.clearDefaults(packageName); 816 } catch (RemoteException e) { 817 Log.e(TAG, "mUsbManager.clearDefaults", e); 818 } 819 mActivitiesButton.setEnabled(false); 820 } else if(v == mClearDataButton) { 821 if (mAppEntry.info.manageSpaceActivityName != null) { 822 Intent intent = new Intent(Intent.ACTION_DEFAULT); 823 intent.setClassName(mAppEntry.info.packageName, 824 mAppEntry.info.manageSpaceActivityName); 825 startActivityForResult(intent, -1); 826 } else { 827 showDialogInner(DLG_CLEAR_DATA, 0); 828 } 829 } else if (v == mClearCacheButton) { 830 // Lazy initialization of observer 831 if (mClearCacheObserver == null) { 832 mClearCacheObserver = new ClearCacheObserver(); 833 } 834 mPm.deleteApplicationCacheFiles(packageName, mClearCacheObserver); 835 } else if (v == mForceStopButton) { 836 showDialogInner(DLG_FORCE_STOP, 0); 837 //forceStopPackage(mAppInfo.packageName); 838 } else if (v == mMoveAppButton) { 839 if (mPackageMoveObserver == null) { 840 mPackageMoveObserver = new PackageMoveObserver(); 841 } 842 int moveFlags = (mAppEntry.info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0 ? 843 PackageManager.MOVE_INTERNAL : PackageManager.MOVE_EXTERNAL_MEDIA; 844 mMoveInProgress = true; 845 refreshButtons(); 846 mPm.movePackage(mAppEntry.info.packageName, mPackageMoveObserver, moveFlags); 847 } 848 } 849} 850 851