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