InstalledAppDetails.java revision 3465b67740e17711af2b36b09e2250a02275d860
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.telephony.ISms; 20import com.android.internal.telephony.SmsUsageMonitor; 21import com.android.settings.R; 22import com.android.settings.Utils; 23import com.android.settings.applications.ApplicationsState.AppEntry; 24 25import android.app.Activity; 26import android.app.ActivityManager; 27import android.app.AlertDialog; 28import android.app.Dialog; 29import android.app.DialogFragment; 30import android.app.Fragment; 31import android.app.INotificationManager; 32import android.app.admin.DevicePolicyManager; 33import android.appwidget.AppWidgetManager; 34import android.content.BroadcastReceiver; 35import android.content.ComponentName; 36import android.content.Context; 37import android.content.DialogInterface; 38import android.content.Intent; 39import android.content.IntentFilter; 40import android.content.pm.ApplicationInfo; 41import android.content.pm.IPackageDataObserver; 42import android.content.pm.IPackageMoveObserver; 43import android.content.pm.PackageInfo; 44import android.content.pm.PackageManager; 45import android.content.pm.ResolveInfo; 46import android.content.pm.PackageManager.NameNotFoundException; 47import android.content.res.Resources; 48import android.hardware.usb.IUsbManager; 49import android.net.Uri; 50import android.os.AsyncTask; 51import android.os.Bundle; 52import android.os.Environment; 53import android.os.Handler; 54import android.os.IBinder; 55import android.os.Message; 56import android.os.RemoteException; 57import android.os.ServiceManager; 58import android.preference.PreferenceActivity; 59import android.text.SpannableString; 60import android.text.TextUtils; 61import android.text.format.Formatter; 62import android.text.style.BulletSpan; 63import android.util.Log; 64 65import java.lang.ref.WeakReference; 66import java.util.ArrayList; 67import java.util.List; 68import android.view.LayoutInflater; 69import android.view.View; 70import android.view.ViewGroup; 71import android.widget.AdapterView; 72import android.widget.AppSecurityPermissions; 73import android.widget.ArrayAdapter; 74import android.widget.Button; 75import android.widget.CheckBox; 76import android.widget.CompoundButton; 77import android.widget.ImageView; 78import android.widget.LinearLayout; 79import android.widget.Spinner; 80import android.widget.TextView; 81 82/** 83 * Activity to display application information from Settings. This activity presents 84 * extended information associated with a package like code, data, total size, permissions 85 * used by the application and also the set of default launchable activities. 86 * For system applications, an option to clear user data is displayed only if data size is > 0. 87 * System applications that do not want clear user data do not have this option. 88 * For non-system applications, there is no option to clear data. Instead there is an option to 89 * uninstall the application. 90 */ 91public class InstalledAppDetails extends Fragment 92 implements View.OnClickListener, CompoundButton.OnCheckedChangeListener, 93 ApplicationsState.Callbacks { 94 private static final String TAG="InstalledAppDetails"; 95 static final boolean SUPPORT_DISABLE_APPS = true; 96 private static final boolean localLOGV = false; 97 98 public static final String ARG_PACKAGE_NAME = "package"; 99 100 private PackageManager mPm; 101 private IUsbManager mUsbManager; 102 private AppWidgetManager mAppWidgetManager; 103 private DevicePolicyManager mDpm; 104 private ISms mSmsManager; 105 private ApplicationsState mState; 106 private ApplicationsState.Session mSession; 107 private ApplicationsState.AppEntry mAppEntry; 108 private PackageInfo mPackageInfo; 109 private CanBeOnSdCardChecker mCanBeOnSdCardChecker; 110 private View mRootView; 111 private Button mUninstallButton; 112 private boolean mMoveInProgress = false; 113 private boolean mUpdatedSysApp = false; 114 private Button mActivitiesButton; 115 private View mScreenCompatSection; 116 private CheckBox mAskCompatibilityCB; 117 private CheckBox mEnableCompatibilityCB; 118 private boolean mCanClearData = true; 119 private TextView mAppVersion; 120 private TextView mTotalSize; 121 private TextView mAppSize; 122 private TextView mDataSize; 123 private TextView mExternalCodeSize; 124 private TextView mExternalDataSize; 125 private ClearUserDataObserver mClearDataObserver; 126 // Views related to cache info 127 private TextView mCacheSize; 128 private Button mClearCacheButton; 129 private ClearCacheObserver mClearCacheObserver; 130 private Button mForceStopButton; 131 private Button mClearDataButton; 132 private Button mMoveAppButton; 133 private CompoundButton mNotificationSwitch; 134 135 private PackageMoveObserver mPackageMoveObserver; 136 137 private boolean mHaveSizes = false; 138 private long mLastCodeSize = -1; 139 private long mLastDataSize = -1; 140 private long mLastExternalCodeSize = -1; 141 private long mLastExternalDataSize = -1; 142 private long mLastCacheSize = -1; 143 private long mLastTotalSize = -1; 144 145 //internal constants used in Handler 146 private static final int OP_SUCCESSFUL = 1; 147 private static final int OP_FAILED = 2; 148 private static final int CLEAR_USER_DATA = 1; 149 private static final int CLEAR_CACHE = 3; 150 private static final int PACKAGE_MOVE = 4; 151 152 // invalid size value used initially and also when size retrieval through PackageManager 153 // fails for whatever reason 154 private static final int SIZE_INVALID = -1; 155 156 // Resource strings 157 private CharSequence mInvalidSizeStr; 158 private CharSequence mComputingStr; 159 160 // Dialog identifiers used in showDialog 161 private static final int DLG_BASE = 0; 162 private static final int DLG_CLEAR_DATA = DLG_BASE + 1; 163 private static final int DLG_FACTORY_RESET = DLG_BASE + 2; 164 private static final int DLG_APP_NOT_FOUND = DLG_BASE + 3; 165 private static final int DLG_CANNOT_CLEAR_DATA = DLG_BASE + 4; 166 private static final int DLG_FORCE_STOP = DLG_BASE + 5; 167 private static final int DLG_MOVE_FAILED = DLG_BASE + 6; 168 private static final int DLG_DISABLE = DLG_BASE + 7; 169 private static final int DLG_DISABLE_NOTIFICATIONS = DLG_BASE + 8; 170 171 private Handler mHandler = new Handler() { 172 public void handleMessage(Message msg) { 173 // If the fragment is gone, don't process any more messages. 174 if (getView() == null) { 175 return; 176 } 177 switch (msg.what) { 178 case CLEAR_USER_DATA: 179 processClearMsg(msg); 180 break; 181 case CLEAR_CACHE: 182 // Refresh size info 183 mState.requestSize(mAppEntry.info.packageName); 184 break; 185 case PACKAGE_MOVE: 186 processMoveMsg(msg); 187 break; 188 default: 189 break; 190 } 191 } 192 }; 193 194 class ClearUserDataObserver extends IPackageDataObserver.Stub { 195 public void onRemoveCompleted(final String packageName, final boolean succeeded) { 196 final Message msg = mHandler.obtainMessage(CLEAR_USER_DATA); 197 msg.arg1 = succeeded?OP_SUCCESSFUL:OP_FAILED; 198 mHandler.sendMessage(msg); 199 } 200 } 201 202 class ClearCacheObserver extends IPackageDataObserver.Stub { 203 public void onRemoveCompleted(final String packageName, final boolean succeeded) { 204 final Message msg = mHandler.obtainMessage(CLEAR_CACHE); 205 msg.arg1 = succeeded ? OP_SUCCESSFUL:OP_FAILED; 206 mHandler.sendMessage(msg); 207 } 208 } 209 210 class PackageMoveObserver extends IPackageMoveObserver.Stub { 211 public void packageMoved(String packageName, int returnCode) throws RemoteException { 212 final Message msg = mHandler.obtainMessage(PACKAGE_MOVE); 213 msg.arg1 = returnCode; 214 mHandler.sendMessage(msg); 215 } 216 } 217 218 private String getSizeStr(long size) { 219 if (size == SIZE_INVALID) { 220 return mInvalidSizeStr.toString(); 221 } 222 return Formatter.formatFileSize(getActivity(), size); 223 } 224 225 private void initDataButtons() { 226 if ((mAppEntry.info.flags&(ApplicationInfo.FLAG_SYSTEM 227 | ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA)) 228 == ApplicationInfo.FLAG_SYSTEM 229 || mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) { 230 mClearDataButton.setText(R.string.clear_user_data_text); 231 mClearDataButton.setEnabled(false); 232 mCanClearData = false; 233 } else { 234 if (mAppEntry.info.manageSpaceActivityName != null) { 235 mClearDataButton.setText(R.string.manage_space_text); 236 } else { 237 mClearDataButton.setText(R.string.clear_user_data_text); 238 } 239 mClearDataButton.setOnClickListener(this); 240 } 241 } 242 243 private CharSequence getMoveErrMsg(int errCode) { 244 switch (errCode) { 245 case PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE: 246 return getActivity().getString(R.string.insufficient_storage); 247 case PackageManager.MOVE_FAILED_DOESNT_EXIST: 248 return getActivity().getString(R.string.does_not_exist); 249 case PackageManager.MOVE_FAILED_FORWARD_LOCKED: 250 return getActivity().getString(R.string.app_forward_locked); 251 case PackageManager.MOVE_FAILED_INVALID_LOCATION: 252 return getActivity().getString(R.string.invalid_location); 253 case PackageManager.MOVE_FAILED_SYSTEM_PACKAGE: 254 return getActivity().getString(R.string.system_package); 255 case PackageManager.MOVE_FAILED_INTERNAL_ERROR: 256 return ""; 257 } 258 return ""; 259 } 260 261 private void initMoveButton() { 262 if (Environment.isExternalStorageEmulated()) { 263 mMoveAppButton.setVisibility(View.INVISIBLE); 264 return; 265 } 266 boolean dataOnly = false; 267 dataOnly = (mPackageInfo == null) && (mAppEntry != null); 268 boolean moveDisable = true; 269 if (dataOnly) { 270 mMoveAppButton.setText(R.string.move_app); 271 } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) { 272 mMoveAppButton.setText(R.string.move_app_to_internal); 273 // Always let apps move to internal storage from sdcard. 274 moveDisable = false; 275 } else { 276 mMoveAppButton.setText(R.string.move_app_to_sdcard); 277 mCanBeOnSdCardChecker.init(); 278 moveDisable = !mCanBeOnSdCardChecker.check(mAppEntry.info); 279 } 280 if (moveDisable) { 281 mMoveAppButton.setEnabled(false); 282 } else { 283 mMoveAppButton.setOnClickListener(this); 284 mMoveAppButton.setEnabled(true); 285 } 286 } 287 288 private boolean isThisASystemPackage() { 289 try { 290 PackageInfo sys = mPm.getPackageInfo("android", PackageManager.GET_SIGNATURES); 291 return (mPackageInfo != null && mPackageInfo.signatures != null && 292 sys.signatures[0].equals(mPackageInfo.signatures[0])); 293 } catch (PackageManager.NameNotFoundException e) { 294 return false; 295 } 296 } 297 298 private void initUninstallButtons() { 299 mUpdatedSysApp = (mAppEntry.info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; 300 boolean enabled = true; 301 if (mUpdatedSysApp) { 302 mUninstallButton.setText(R.string.app_factory_reset); 303 } else { 304 if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 305 enabled = false; 306 if (SUPPORT_DISABLE_APPS) { 307 try { 308 // Try to prevent the user from bricking their phone 309 // by not allowing disabling of apps signed with the 310 // system cert and any launcher app in the system. 311 PackageInfo sys = mPm.getPackageInfo("android", 312 PackageManager.GET_SIGNATURES); 313 Intent intent = new Intent(Intent.ACTION_MAIN); 314 intent.addCategory(Intent.CATEGORY_HOME); 315 intent.setPackage(mAppEntry.info.packageName); 316 List<ResolveInfo> homes = mPm.queryIntentActivities(intent, 0); 317 if ((homes != null && homes.size() > 0) || isThisASystemPackage()) { 318 // Disable button for core system applications. 319 mUninstallButton.setText(R.string.disable_text); 320 } else if (mAppEntry.info.enabled) { 321 mUninstallButton.setText(R.string.disable_text); 322 enabled = true; 323 } else { 324 mUninstallButton.setText(R.string.enable_text); 325 enabled = true; 326 } 327 } catch (PackageManager.NameNotFoundException e) { 328 Log.w(TAG, "Unable to get package info", e); 329 } 330 } 331 } else if ((mPackageInfo.applicationInfo.flags 332 & ApplicationInfo.FLAG_INSTALLED) == 0) { 333 mUninstallButton.setText(R.string.install_text); 334 } else { 335 mUninstallButton.setText(R.string.uninstall_text); 336 } 337 } 338 // If this is a device admin, it can't be uninstall or disabled. 339 // We do this here so the text of the button is still set correctly. 340 if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) { 341 enabled = false; 342 } 343 mUninstallButton.setEnabled(enabled); 344 if (enabled) { 345 // Register listener 346 mUninstallButton.setOnClickListener(this); 347 } 348 } 349 350 private void initNotificationButton() { 351 INotificationManager nm = INotificationManager.Stub.asInterface( 352 ServiceManager.getService(Context.NOTIFICATION_SERVICE)); 353 boolean enabled = true; // default on 354 try { 355 enabled = nm.areNotificationsEnabledForPackage(mAppEntry.info.packageName); 356 } catch (android.os.RemoteException ex) { 357 // this does not bode well 358 } 359 mNotificationSwitch.setChecked(enabled); 360 if (isThisASystemPackage()) { 361 mNotificationSwitch.setEnabled(false); 362 } else { 363 mNotificationSwitch.setEnabled(true); 364 mNotificationSwitch.setOnCheckedChangeListener(this); 365 } 366 } 367 368 /** Called when the activity is first created. */ 369 @Override 370 public void onCreate(Bundle icicle) { 371 super.onCreate(icicle); 372 373 mState = ApplicationsState.getInstance(getActivity().getApplication()); 374 mSession = mState.newSession(this); 375 mPm = getActivity().getPackageManager(); 376 IBinder b = ServiceManager.getService(Context.USB_SERVICE); 377 mUsbManager = IUsbManager.Stub.asInterface(b); 378 mAppWidgetManager = AppWidgetManager.getInstance(getActivity()); 379 mDpm = (DevicePolicyManager)getActivity().getSystemService(Context.DEVICE_POLICY_SERVICE); 380 mSmsManager = ISms.Stub.asInterface(ServiceManager.getService("isms")); 381 382 mCanBeOnSdCardChecker = new CanBeOnSdCardChecker(); 383 } 384 385 @Override 386 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 387 View view = mRootView = inflater.inflate(R.layout.installed_app_details, null); 388 389 mComputingStr = getActivity().getText(R.string.computing_size); 390 391 // Set default values on sizes 392 mTotalSize = (TextView)view.findViewById(R.id.total_size_text); 393 mAppSize = (TextView)view.findViewById(R.id.application_size_text); 394 mDataSize = (TextView)view.findViewById(R.id.data_size_text); 395 mExternalCodeSize = (TextView)view.findViewById(R.id.external_code_size_text); 396 mExternalDataSize = (TextView)view.findViewById(R.id.external_data_size_text); 397 398 if (Environment.isExternalStorageEmulated()) { 399 ((View)mExternalCodeSize.getParent()).setVisibility(View.GONE); 400 ((View)mExternalDataSize.getParent()).setVisibility(View.GONE); 401 } 402 403 // Get Control button panel 404 View btnPanel = view.findViewById(R.id.control_buttons_panel); 405 mForceStopButton = (Button) btnPanel.findViewById(R.id.left_button); 406 mForceStopButton.setText(R.string.force_stop); 407 mUninstallButton = (Button)btnPanel.findViewById(R.id.right_button); 408 mForceStopButton.setEnabled(false); 409 410 // Initialize clear data and move install location buttons 411 View data_buttons_panel = view.findViewById(R.id.data_buttons_panel); 412 mClearDataButton = (Button) data_buttons_panel.findViewById(R.id.right_button); 413 mMoveAppButton = (Button) data_buttons_panel.findViewById(R.id.left_button); 414 415 // Cache section 416 mCacheSize = (TextView) view.findViewById(R.id.cache_size_text); 417 mClearCacheButton = (Button) view.findViewById(R.id.clear_cache_button); 418 419 mActivitiesButton = (Button)view.findViewById(R.id.clear_activities_button); 420 421 // Screen compatibility control 422 mScreenCompatSection = view.findViewById(R.id.screen_compatibility_section); 423 mAskCompatibilityCB = (CheckBox)view.findViewById(R.id.ask_compatibility_cb); 424 mEnableCompatibilityCB = (CheckBox)view.findViewById(R.id.enable_compatibility_cb); 425 426 mNotificationSwitch = (CompoundButton) view.findViewById(R.id.notification_switch); 427 428 return view; 429 } 430 431 // Utility method to set applicaiton label and icon. 432 private void setAppLabelAndIcon(PackageInfo pkgInfo) { 433 View appSnippet = mRootView.findViewById(R.id.app_snippet); 434 ImageView icon = (ImageView) appSnippet.findViewById(R.id.app_icon); 435 mState.ensureIcon(mAppEntry); 436 icon.setImageDrawable(mAppEntry.icon); 437 // Set application name. 438 TextView label = (TextView) appSnippet.findViewById(R.id.app_name); 439 label.setText(mAppEntry.label); 440 // Version number of application 441 mAppVersion = (TextView) appSnippet.findViewById(R.id.app_size); 442 443 if (pkgInfo != null && pkgInfo.versionName != null) { 444 mAppVersion.setVisibility(View.VISIBLE); 445 mAppVersion.setText(getActivity().getString(R.string.version_text, 446 String.valueOf(pkgInfo.versionName))); 447 } else { 448 mAppVersion.setVisibility(View.INVISIBLE); 449 } 450 } 451 452 @Override 453 public void onResume() { 454 super.onResume(); 455 456 mSession.resume(); 457 if (!refreshUi()) { 458 setIntentAndFinish(true, true); 459 } 460 } 461 462 @Override 463 public void onPause() { 464 super.onPause(); 465 mSession.pause(); 466 } 467 468 @Override 469 public void onAllSizesComputed() { 470 } 471 472 @Override 473 public void onPackageIconChanged() { 474 } 475 476 @Override 477 public void onPackageListChanged() { 478 refreshUi(); 479 } 480 481 @Override 482 public void onRebuildComplete(ArrayList<AppEntry> apps) { 483 } 484 485 @Override 486 public void onPackageSizeChanged(String packageName) { 487 if (packageName.equals(mAppEntry.info.packageName)) { 488 refreshSizeInfo(); 489 } 490 } 491 492 @Override 493 public void onRunningStateChanged(boolean running) { 494 } 495 496 private boolean refreshUi() { 497 if (mMoveInProgress) { 498 return true; 499 } 500 final Bundle args = getArguments(); 501 String packageName = (args != null) ? args.getString(ARG_PACKAGE_NAME) : null; 502 if (packageName == null) { 503 Intent intent = (args == null) ? 504 getActivity().getIntent() : (Intent) args.getParcelable("intent"); 505 if (intent != null) { 506 packageName = intent.getData().getSchemeSpecificPart(); 507 } 508 } 509 mAppEntry = mState.getEntry(packageName); 510 511 if (mAppEntry == null) { 512 return false; // onCreate must have failed, make sure to exit 513 } 514 515 // Get application info again to refresh changed properties of application 516 try { 517 mPackageInfo = mPm.getPackageInfo(mAppEntry.info.packageName, 518 PackageManager.GET_DISABLED_COMPONENTS | 519 PackageManager.GET_UNINSTALLED_PACKAGES | 520 PackageManager.GET_SIGNATURES); 521 } catch (NameNotFoundException e) { 522 Log.e(TAG, "Exception when retrieving package:" + mAppEntry.info.packageName, e); 523 return false; // onCreate must have failed, make sure to exit 524 } 525 526 // Get list of preferred activities 527 List<ComponentName> prefActList = new ArrayList<ComponentName>(); 528 529 // Intent list cannot be null. so pass empty list 530 List<IntentFilter> intentList = new ArrayList<IntentFilter>(); 531 mPm.getPreferredActivities(intentList, prefActList, packageName); 532 if (localLOGV) 533 Log.i(TAG, "Have " + prefActList.size() + " number of activities in preferred list"); 534 boolean hasUsbDefaults = false; 535 try { 536 hasUsbDefaults = mUsbManager.hasDefaults(packageName); 537 } catch (RemoteException e) { 538 Log.e(TAG, "mUsbManager.hasDefaults", e); 539 } 540 boolean hasBindAppWidgetPermission = 541 mAppWidgetManager.hasBindAppWidgetPermission(mAppEntry.info.packageName); 542 543 TextView autoLaunchTitleView = (TextView) mRootView.findViewById(R.id.auto_launch_title); 544 TextView autoLaunchView = (TextView) mRootView.findViewById(R.id.auto_launch); 545 boolean autoLaunchEnabled = prefActList.size() > 0 || hasUsbDefaults; 546 if (!autoLaunchEnabled && !hasBindAppWidgetPermission) { 547 resetLaunchDefaultsUi(autoLaunchTitleView, autoLaunchView); 548 } else { 549 boolean useBullets = hasBindAppWidgetPermission && autoLaunchEnabled; 550 551 if (hasBindAppWidgetPermission) { 552 autoLaunchTitleView.setText(R.string.auto_launch_label_generic); 553 } else { 554 autoLaunchTitleView.setText(R.string.auto_launch_label); 555 } 556 557 CharSequence text = null; 558 int bulletIndent = getResources() 559 .getDimensionPixelSize(R.dimen.installed_app_details_bullet_offset); 560 if (autoLaunchEnabled) { 561 CharSequence autoLaunchEnableText = getText(R.string.auto_launch_enable_text); 562 SpannableString s = new SpannableString(autoLaunchEnableText); 563 if (useBullets) { 564 s.setSpan(new BulletSpan(bulletIndent), 0, autoLaunchEnableText.length(), 0); 565 } 566 text = (text == null) ? 567 TextUtils.concat(s, "\n") : TextUtils.concat(text, "\n", s, "\n"); 568 } 569 if (hasBindAppWidgetPermission) { 570 CharSequence alwaysAllowBindAppWidgetsText = 571 getText(R.string.always_allow_bind_appwidgets_text); 572 SpannableString s = new SpannableString(alwaysAllowBindAppWidgetsText); 573 if (useBullets) { 574 s.setSpan(new BulletSpan(bulletIndent), 575 0, alwaysAllowBindAppWidgetsText.length(), 0); 576 } 577 text = (text == null) ? 578 TextUtils.concat(s, "\n") : TextUtils.concat(text, "\n", s, "\n"); 579 } 580 autoLaunchView.setText(text); 581 mActivitiesButton.setEnabled(true); 582 mActivitiesButton.setOnClickListener(this); 583 } 584 585 // Screen compatibility section. 586 ActivityManager am = (ActivityManager) 587 getActivity().getSystemService(Context.ACTIVITY_SERVICE); 588 int compatMode = am.getPackageScreenCompatMode(packageName); 589 // For now these are always off; this is the old UI model which we 590 // are no longer using. 591 if (false && (compatMode == ActivityManager.COMPAT_MODE_DISABLED 592 || compatMode == ActivityManager.COMPAT_MODE_ENABLED)) { 593 mScreenCompatSection.setVisibility(View.VISIBLE); 594 mAskCompatibilityCB.setChecked(am.getPackageAskScreenCompat(packageName)); 595 mAskCompatibilityCB.setOnCheckedChangeListener(this); 596 mEnableCompatibilityCB.setChecked(compatMode == ActivityManager.COMPAT_MODE_ENABLED); 597 mEnableCompatibilityCB.setOnCheckedChangeListener(this); 598 } else { 599 mScreenCompatSection.setVisibility(View.GONE); 600 } 601 602 // Security permissions section 603 LinearLayout permsView = (LinearLayout) mRootView.findViewById(R.id.permissions_section); 604 AppSecurityPermissions asp = new AppSecurityPermissions(getActivity(), packageName); 605 int premiumSmsPermission = getPremiumSmsPermission(packageName); 606 // Premium SMS permission implies the app also has SEND_SMS permission, so the original 607 // application permissions list doesn't have to be shown/hidden separately. The premium 608 // SMS subsection should only be visible if the app has tried to send to a premium SMS. 609 if (asp.getPermissionCount() > 0 610 || premiumSmsPermission != SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) { 611 permsView.setVisibility(View.VISIBLE); 612 } else { 613 permsView.setVisibility(View.GONE); 614 } 615 // Premium SMS permission subsection 616 TextView securityBillingDesc = (TextView) permsView.findViewById( 617 R.id.security_settings_billing_desc); 618 LinearLayout securityBillingList = (LinearLayout) permsView.findViewById( 619 R.id.security_settings_billing_list); 620 if (premiumSmsPermission != SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) { 621 // Show the premium SMS permission selector 622 securityBillingDesc.setVisibility(View.VISIBLE); 623 securityBillingList.setVisibility(View.VISIBLE); 624 Spinner spinner = (Spinner) permsView.findViewById( 625 R.id.security_settings_premium_sms_list); 626 ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(getActivity(), 627 R.array.security_settings_premium_sms_values, 628 android.R.layout.simple_spinner_item); 629 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 630 spinner.setAdapter(adapter); 631 // List items are in the same order as SmsUsageMonitor constants, offset by 1. 632 spinner.setSelection(premiumSmsPermission - 1); 633 spinner.setOnItemSelectedListener(new PremiumSmsSelectionListener( 634 packageName, mSmsManager)); 635 } else { 636 // Hide the premium SMS permission selector 637 securityBillingDesc.setVisibility(View.GONE); 638 securityBillingList.setVisibility(View.GONE); 639 } 640 // App permissions subsection 641 if (asp.getPermissionCount() > 0) { 642 // Make the security sections header visible 643 LinearLayout securityList = (LinearLayout) permsView.findViewById( 644 R.id.security_settings_list); 645 securityList.removeAllViews(); 646 securityList.addView(asp.getPermissionsView()); 647 // If this app is running under a shared user ID with other apps, 648 // update the description to explain this. 649 String[] packages = mPm.getPackagesForUid(mPackageInfo.applicationInfo.uid); 650 if (packages != null && packages.length > 1) { 651 ArrayList<CharSequence> pnames = new ArrayList<CharSequence>(); 652 for (int i=0; i<packages.length; i++) { 653 String pkg = packages[i]; 654 if (mPackageInfo.packageName.equals(pkg)) { 655 continue; 656 } 657 try { 658 ApplicationInfo ainfo = mPm.getApplicationInfo(pkg, 0); 659 pnames.add(ainfo.loadLabel(mPm)); 660 } catch (PackageManager.NameNotFoundException e) { 661 } 662 } 663 final int N = pnames.size(); 664 if (N > 0) { 665 final Resources res = getActivity().getResources(); 666 String appListStr; 667 if (N == 1) { 668 appListStr = pnames.get(0).toString(); 669 } else if (N == 2) { 670 appListStr = res.getString(R.string.join_two_items, pnames.get(0), 671 pnames.get(1)); 672 } else { 673 appListStr = pnames.get(N-2).toString(); 674 for (int i=N-3; i>=0; i--) { 675 appListStr = res.getString(i == 0 ? R.string.join_many_items_first 676 : R.string.join_many_items_middle, pnames.get(i), appListStr); 677 } 678 appListStr = res.getString(R.string.join_many_items_last, 679 appListStr, pnames.get(N-1)); 680 } 681 TextView descr = (TextView) mRootView.findViewById( 682 R.id.security_settings_desc); 683 descr.setText(res.getString(R.string.security_settings_desc_multi, 684 mPackageInfo.applicationInfo.loadLabel(mPm), appListStr)); 685 } 686 } 687 } 688 689 checkForceStop(); 690 setAppLabelAndIcon(mPackageInfo); 691 refreshButtons(); 692 refreshSizeInfo(); 693 return true; 694 } 695 696 private static class PremiumSmsSelectionListener implements AdapterView.OnItemSelectedListener { 697 private final String mPackageName; 698 private final ISms mSmsManager; 699 700 PremiumSmsSelectionListener(String packageName, ISms smsManager) { 701 mPackageName = packageName; 702 mSmsManager = smsManager; 703 } 704 705 @Override 706 public void onItemSelected(AdapterView<?> parent, View view, int position, 707 long id) { 708 if (position >= 0 && position < 3) { 709 Log.d(TAG, "Selected premium SMS policy " + position); 710 setPremiumSmsPermission(mPackageName, (position + 1)); 711 } else { 712 Log.e(TAG, "Error: unknown premium SMS policy " + position); 713 } 714 } 715 716 @Override 717 public void onNothingSelected(AdapterView<?> parent) { 718 // Ignored 719 } 720 721 private void setPremiumSmsPermission(String packageName, int permission) { 722 try { 723 if (mSmsManager != null) { 724 mSmsManager.setPremiumSmsPermission(packageName, permission); 725 } 726 } catch (RemoteException ex) { 727 // ignored 728 } 729 } 730 } 731 732 private void resetLaunchDefaultsUi(TextView title, TextView autoLaunchView) { 733 title.setText(R.string.auto_launch_label); 734 autoLaunchView.setText(R.string.auto_launch_disable_text); 735 // Disable clear activities button 736 mActivitiesButton.setEnabled(false); 737 } 738 739 private void setIntentAndFinish(boolean finish, boolean appChanged) { 740 if(localLOGV) Log.i(TAG, "appChanged="+appChanged); 741 Intent intent = new Intent(); 742 intent.putExtra(ManageApplications.APP_CHG, appChanged); 743 PreferenceActivity pa = (PreferenceActivity)getActivity(); 744 pa.finishPreferencePanel(this, Activity.RESULT_OK, intent); 745 } 746 747 private void refreshSizeInfo() { 748 if (mAppEntry.size == ApplicationsState.SIZE_INVALID 749 || mAppEntry.size == ApplicationsState.SIZE_UNKNOWN) { 750 mLastCodeSize = mLastDataSize = mLastCacheSize = mLastTotalSize = -1; 751 if (!mHaveSizes) { 752 mAppSize.setText(mComputingStr); 753 mDataSize.setText(mComputingStr); 754 mCacheSize.setText(mComputingStr); 755 mTotalSize.setText(mComputingStr); 756 } 757 mClearDataButton.setEnabled(false); 758 mClearCacheButton.setEnabled(false); 759 760 } else { 761 mHaveSizes = true; 762 long codeSize = mAppEntry.codeSize; 763 long dataSize = mAppEntry.dataSize; 764 if (Environment.isExternalStorageEmulated()) { 765 codeSize += mAppEntry.externalCodeSize; 766 dataSize += mAppEntry.externalDataSize; 767 } else { 768 if (mLastExternalCodeSize != mAppEntry.externalCodeSize) { 769 mLastExternalCodeSize = mAppEntry.externalCodeSize; 770 mExternalCodeSize.setText(getSizeStr(mAppEntry.externalCodeSize)); 771 } 772 if (mLastExternalDataSize != mAppEntry.externalDataSize) { 773 mLastExternalDataSize = mAppEntry.externalDataSize; 774 mExternalDataSize.setText(getSizeStr( mAppEntry.externalDataSize)); 775 } 776 } 777 if (mLastCodeSize != codeSize) { 778 mLastCodeSize = codeSize; 779 mAppSize.setText(getSizeStr(codeSize)); 780 } 781 if (mLastDataSize != dataSize) { 782 mLastDataSize = dataSize; 783 mDataSize.setText(getSizeStr(dataSize)); 784 } 785 long cacheSize = mAppEntry.cacheSize + mAppEntry.externalCacheSize; 786 if (mLastCacheSize != cacheSize) { 787 mLastCacheSize = cacheSize; 788 mCacheSize.setText(getSizeStr(cacheSize)); 789 } 790 if (mLastTotalSize != mAppEntry.size) { 791 mLastTotalSize = mAppEntry.size; 792 mTotalSize.setText(getSizeStr(mAppEntry.size)); 793 } 794 795 if ((mAppEntry.dataSize+ mAppEntry.externalDataSize) <= 0 || !mCanClearData) { 796 mClearDataButton.setEnabled(false); 797 } else { 798 mClearDataButton.setEnabled(true); 799 mClearDataButton.setOnClickListener(this); 800 } 801 if (cacheSize <= 0) { 802 mClearCacheButton.setEnabled(false); 803 } else { 804 mClearCacheButton.setEnabled(true); 805 mClearCacheButton.setOnClickListener(this); 806 } 807 } 808 } 809 810 /* 811 * Private method to handle clear message notification from observer when 812 * the async operation from PackageManager is complete 813 */ 814 private void processClearMsg(Message msg) { 815 int result = msg.arg1; 816 String packageName = mAppEntry.info.packageName; 817 mClearDataButton.setText(R.string.clear_user_data_text); 818 if(result == OP_SUCCESSFUL) { 819 Log.i(TAG, "Cleared user data for package : "+packageName); 820 mState.requestSize(mAppEntry.info.packageName); 821 } else { 822 mClearDataButton.setEnabled(true); 823 } 824 checkForceStop(); 825 } 826 827 private void refreshButtons() { 828 if (!mMoveInProgress) { 829 initUninstallButtons(); 830 initDataButtons(); 831 initMoveButton(); 832 initNotificationButton(); 833 } else { 834 mMoveAppButton.setText(R.string.moving); 835 mMoveAppButton.setEnabled(false); 836 mUninstallButton.setEnabled(false); 837 } 838 } 839 840 private void processMoveMsg(Message msg) { 841 int result = msg.arg1; 842 String packageName = mAppEntry.info.packageName; 843 // Refresh the button attributes. 844 mMoveInProgress = false; 845 if (result == PackageManager.MOVE_SUCCEEDED) { 846 Log.i(TAG, "Moved resources for " + packageName); 847 // Refresh size information again. 848 mState.requestSize(mAppEntry.info.packageName); 849 } else { 850 showDialogInner(DLG_MOVE_FAILED, result); 851 } 852 refreshUi(); 853 } 854 855 /* 856 * Private method to initiate clearing user data when the user clicks the clear data 857 * button for a system package 858 */ 859 private void initiateClearUserData() { 860 mClearDataButton.setEnabled(false); 861 // Invoke uninstall or clear user data based on sysPackage 862 String packageName = mAppEntry.info.packageName; 863 Log.i(TAG, "Clearing user data for package : " + packageName); 864 if (mClearDataObserver == null) { 865 mClearDataObserver = new ClearUserDataObserver(); 866 } 867 ActivityManager am = (ActivityManager) 868 getActivity().getSystemService(Context.ACTIVITY_SERVICE); 869 boolean res = am.clearApplicationUserData(packageName, mClearDataObserver); 870 if (!res) { 871 // Clearing data failed for some obscure reason. Just log error for now 872 Log.i(TAG, "Couldnt clear application user data for package:"+packageName); 873 showDialogInner(DLG_CANNOT_CLEAR_DATA, 0); 874 } else { 875 mClearDataButton.setText(R.string.recompute_size); 876 } 877 } 878 879 private void showDialogInner(int id, int moveErrorCode) { 880 DialogFragment newFragment = MyAlertDialogFragment.newInstance(id, moveErrorCode); 881 newFragment.setTargetFragment(this, 0); 882 newFragment.show(getFragmentManager(), "dialog " + id); 883 } 884 885 public static class MyAlertDialogFragment extends DialogFragment { 886 887 public static MyAlertDialogFragment newInstance(int id, int moveErrorCode) { 888 MyAlertDialogFragment frag = new MyAlertDialogFragment(); 889 Bundle args = new Bundle(); 890 args.putInt("id", id); 891 args.putInt("moveError", moveErrorCode); 892 frag.setArguments(args); 893 return frag; 894 } 895 896 InstalledAppDetails getOwner() { 897 return (InstalledAppDetails)getTargetFragment(); 898 } 899 900 @Override 901 public Dialog onCreateDialog(Bundle savedInstanceState) { 902 int id = getArguments().getInt("id"); 903 int moveErrorCode = getArguments().getInt("moveError"); 904 switch (id) { 905 case DLG_CLEAR_DATA: 906 return new AlertDialog.Builder(getActivity()) 907 .setTitle(getActivity().getText(R.string.clear_data_dlg_title)) 908 .setIconAttribute(android.R.attr.alertDialogIcon) 909 .setMessage(getActivity().getText(R.string.clear_data_dlg_text)) 910 .setPositiveButton(R.string.dlg_ok, 911 new DialogInterface.OnClickListener() { 912 public void onClick(DialogInterface dialog, int which) { 913 // Clear user data here 914 getOwner().initiateClearUserData(); 915 } 916 }) 917 .setNegativeButton(R.string.dlg_cancel, null) 918 .create(); 919 case DLG_FACTORY_RESET: 920 return new AlertDialog.Builder(getActivity()) 921 .setTitle(getActivity().getText(R.string.app_factory_reset_dlg_title)) 922 .setIconAttribute(android.R.attr.alertDialogIcon) 923 .setMessage(getActivity().getText(R.string.app_factory_reset_dlg_text)) 924 .setPositiveButton(R.string.dlg_ok, 925 new DialogInterface.OnClickListener() { 926 public void onClick(DialogInterface dialog, int which) { 927 // Clear user data here 928 getOwner().uninstallPkg(getOwner().mAppEntry.info.packageName); 929 } 930 }) 931 .setNegativeButton(R.string.dlg_cancel, null) 932 .create(); 933 case DLG_APP_NOT_FOUND: 934 return new AlertDialog.Builder(getActivity()) 935 .setTitle(getActivity().getText(R.string.app_not_found_dlg_title)) 936 .setIconAttribute(android.R.attr.alertDialogIcon) 937 .setMessage(getActivity().getText(R.string.app_not_found_dlg_title)) 938 .setNeutralButton(getActivity().getText(R.string.dlg_ok), 939 new DialogInterface.OnClickListener() { 940 public void onClick(DialogInterface dialog, int which) { 941 //force to recompute changed value 942 getOwner().setIntentAndFinish(true, true); 943 } 944 }) 945 .create(); 946 case DLG_CANNOT_CLEAR_DATA: 947 return new AlertDialog.Builder(getActivity()) 948 .setTitle(getActivity().getText(R.string.clear_failed_dlg_title)) 949 .setIconAttribute(android.R.attr.alertDialogIcon) 950 .setMessage(getActivity().getText(R.string.clear_failed_dlg_text)) 951 .setNeutralButton(R.string.dlg_ok, 952 new DialogInterface.OnClickListener() { 953 public void onClick(DialogInterface dialog, int which) { 954 getOwner().mClearDataButton.setEnabled(false); 955 //force to recompute changed value 956 getOwner().setIntentAndFinish(false, false); 957 } 958 }) 959 .create(); 960 case DLG_FORCE_STOP: 961 return new AlertDialog.Builder(getActivity()) 962 .setTitle(getActivity().getText(R.string.force_stop_dlg_title)) 963 .setIconAttribute(android.R.attr.alertDialogIcon) 964 .setMessage(getActivity().getText(R.string.force_stop_dlg_text)) 965 .setPositiveButton(R.string.dlg_ok, 966 new DialogInterface.OnClickListener() { 967 public void onClick(DialogInterface dialog, int which) { 968 // Force stop 969 getOwner().forceStopPackage(getOwner().mAppEntry.info.packageName); 970 } 971 }) 972 .setNegativeButton(R.string.dlg_cancel, null) 973 .create(); 974 case DLG_MOVE_FAILED: 975 CharSequence msg = getActivity().getString(R.string.move_app_failed_dlg_text, 976 getOwner().getMoveErrMsg(moveErrorCode)); 977 return new AlertDialog.Builder(getActivity()) 978 .setTitle(getActivity().getText(R.string.move_app_failed_dlg_title)) 979 .setIconAttribute(android.R.attr.alertDialogIcon) 980 .setMessage(msg) 981 .setNeutralButton(R.string.dlg_ok, null) 982 .create(); 983 case DLG_DISABLE: 984 return new AlertDialog.Builder(getActivity()) 985 .setTitle(getActivity().getText(R.string.app_disable_dlg_title)) 986 .setIconAttribute(android.R.attr.alertDialogIcon) 987 .setMessage(getActivity().getText(R.string.app_disable_dlg_text)) 988 .setPositiveButton(R.string.dlg_ok, 989 new DialogInterface.OnClickListener() { 990 public void onClick(DialogInterface dialog, int which) { 991 // Disable the app 992 new DisableChanger(getOwner(), getOwner().mAppEntry.info, 993 PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) 994 .execute((Object)null); 995 } 996 }) 997 .setNegativeButton(R.string.dlg_cancel, null) 998 .create(); 999 case DLG_DISABLE_NOTIFICATIONS: 1000 return new AlertDialog.Builder(getActivity()) 1001 .setTitle(getActivity().getText(R.string.app_disable_notifications_dlg_title)) 1002 .setIconAttribute(android.R.attr.alertDialogIcon) 1003 .setMessage(getActivity().getText(R.string.app_disable_notifications_dlg_text)) 1004 .setPositiveButton(R.string.dlg_ok, 1005 new DialogInterface.OnClickListener() { 1006 public void onClick(DialogInterface dialog, int which) { 1007 // Disable the package's notifications 1008 getOwner().setNotificationsEnabled(false); 1009 } 1010 }) 1011 .setNegativeButton(R.string.dlg_cancel, 1012 new DialogInterface.OnClickListener() { 1013 public void onClick(DialogInterface dialog, int which) { 1014 // Re-enable the checkbox 1015 getOwner().mNotificationSwitch.setChecked(true); 1016 } 1017 }) 1018 .create(); 1019 } 1020 throw new IllegalArgumentException("unknown id " + id); 1021 } 1022 } 1023 1024 private void uninstallPkg(String packageName) { 1025 // Create new intent to launch Uninstaller activity 1026 Uri packageURI = Uri.parse("package:"+packageName); 1027 Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI); 1028 startActivity(uninstallIntent); 1029 setIntentAndFinish(true, true); 1030 } 1031 1032 private void forceStopPackage(String pkgName) { 1033 ActivityManager am = (ActivityManager)getActivity().getSystemService( 1034 Context.ACTIVITY_SERVICE); 1035 am.forceStopPackage(pkgName); 1036 mState.invalidatePackage(pkgName); 1037 ApplicationsState.AppEntry newEnt = mState.getEntry(pkgName); 1038 if (newEnt != null) { 1039 mAppEntry = newEnt; 1040 } 1041 checkForceStop(); 1042 } 1043 1044 private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() { 1045 @Override 1046 public void onReceive(Context context, Intent intent) { 1047 updateForceStopButton(getResultCode() != Activity.RESULT_CANCELED); 1048 } 1049 }; 1050 1051 private void updateForceStopButton(boolean enabled) { 1052 mForceStopButton.setEnabled(enabled); 1053 mForceStopButton.setOnClickListener(InstalledAppDetails.this); 1054 } 1055 1056 private void checkForceStop() { 1057 if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) { 1058 // User can't force stop device admin. 1059 updateForceStopButton(false); 1060 } else if ((mAppEntry.info.flags&ApplicationInfo.FLAG_STOPPED) == 0) { 1061 // If the app isn't explicitly stopped, then always show the 1062 // force stop button. 1063 updateForceStopButton(true); 1064 } else { 1065 Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART, 1066 Uri.fromParts("package", mAppEntry.info.packageName, null)); 1067 intent.putExtra(Intent.EXTRA_PACKAGES, new String[] { mAppEntry.info.packageName }); 1068 intent.putExtra(Intent.EXTRA_UID, mAppEntry.info.uid); 1069 getActivity().sendOrderedBroadcast(intent, null, mCheckKillProcessesReceiver, null, 1070 Activity.RESULT_CANCELED, null, null); 1071 } 1072 } 1073 1074 static class DisableChanger extends AsyncTask<Object, Object, Object> { 1075 final PackageManager mPm; 1076 final WeakReference<InstalledAppDetails> mActivity; 1077 final ApplicationInfo mInfo; 1078 final int mState; 1079 1080 DisableChanger(InstalledAppDetails activity, ApplicationInfo info, int state) { 1081 mPm = activity.mPm; 1082 mActivity = new WeakReference<InstalledAppDetails>(activity); 1083 mInfo = info; 1084 mState = state; 1085 } 1086 1087 @Override 1088 protected Object doInBackground(Object... params) { 1089 mPm.setApplicationEnabledSetting(mInfo.packageName, mState, 0); 1090 return null; 1091 } 1092 } 1093 1094 private void setNotificationsEnabled(boolean enabled) { 1095 String packageName = mAppEntry.info.packageName; 1096 INotificationManager nm = INotificationManager.Stub.asInterface( 1097 ServiceManager.getService(Context.NOTIFICATION_SERVICE)); 1098 try { 1099 final boolean enable = mNotificationSwitch.isChecked(); 1100 nm.setNotificationsEnabledForPackage(packageName, enabled); 1101 } catch (android.os.RemoteException ex) { 1102 mNotificationSwitch.setChecked(!enabled); // revert 1103 } 1104 } 1105 1106 private int getPremiumSmsPermission(String packageName) { 1107 try { 1108 if (mSmsManager != null) { 1109 return mSmsManager.getPremiumSmsPermission(packageName); 1110 } 1111 } catch (RemoteException ex) { 1112 // ignored 1113 } 1114 return SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN; 1115 } 1116 1117 /* 1118 * Method implementing functionality of buttons clicked 1119 * @see android.view.View.OnClickListener#onClick(android.view.View) 1120 */ 1121 public void onClick(View v) { 1122 String packageName = mAppEntry.info.packageName; 1123 if(v == mUninstallButton) { 1124 if (mUpdatedSysApp) { 1125 showDialogInner(DLG_FACTORY_RESET, 0); 1126 } else { 1127 if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 1128 if (mAppEntry.info.enabled) { 1129 showDialogInner(DLG_DISABLE, 0); 1130 } else { 1131 new DisableChanger(this, mAppEntry.info, 1132 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) 1133 .execute((Object)null); 1134 } 1135 } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_INSTALLED) == 0) { 1136 try { 1137 mPm.installExistingPackage(packageName); 1138 refreshUi(); 1139 } catch (NameNotFoundException e) { 1140 } 1141 } else { 1142 uninstallPkg(packageName); 1143 } 1144 } 1145 } else if(v == mActivitiesButton) { 1146 mPm.clearPackagePreferredActivities(packageName); 1147 try { 1148 mUsbManager.clearDefaults(packageName); 1149 } catch (RemoteException e) { 1150 Log.e(TAG, "mUsbManager.clearDefaults", e); 1151 } 1152 mAppWidgetManager.setBindAppWidgetPermission(packageName, false); 1153 TextView autoLaunchTitleView = 1154 (TextView) mRootView.findViewById(R.id.auto_launch_title); 1155 TextView autoLaunchView = (TextView) mRootView.findViewById(R.id.auto_launch); 1156 resetLaunchDefaultsUi(autoLaunchTitleView, autoLaunchView); 1157 } else if(v == mClearDataButton) { 1158 if (mAppEntry.info.manageSpaceActivityName != null) { 1159 if (!Utils.isMonkeyRunning()) { 1160 Intent intent = new Intent(Intent.ACTION_DEFAULT); 1161 intent.setClassName(mAppEntry.info.packageName, 1162 mAppEntry.info.manageSpaceActivityName); 1163 startActivityForResult(intent, -1); 1164 } 1165 } else { 1166 showDialogInner(DLG_CLEAR_DATA, 0); 1167 } 1168 } else if (v == mClearCacheButton) { 1169 // Lazy initialization of observer 1170 if (mClearCacheObserver == null) { 1171 mClearCacheObserver = new ClearCacheObserver(); 1172 } 1173 mPm.deleteApplicationCacheFiles(packageName, mClearCacheObserver); 1174 } else if (v == mForceStopButton) { 1175 showDialogInner(DLG_FORCE_STOP, 0); 1176 //forceStopPackage(mAppInfo.packageName); 1177 } else if (v == mMoveAppButton) { 1178 if (mPackageMoveObserver == null) { 1179 mPackageMoveObserver = new PackageMoveObserver(); 1180 } 1181 int moveFlags = (mAppEntry.info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0 ? 1182 PackageManager.MOVE_INTERNAL : PackageManager.MOVE_EXTERNAL_MEDIA; 1183 mMoveInProgress = true; 1184 refreshButtons(); 1185 mPm.movePackage(mAppEntry.info.packageName, mPackageMoveObserver, moveFlags); 1186 } 1187 } 1188 1189 @Override 1190 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 1191 String packageName = mAppEntry.info.packageName; 1192 ActivityManager am = (ActivityManager) 1193 getActivity().getSystemService(Context.ACTIVITY_SERVICE); 1194 if (buttonView == mAskCompatibilityCB) { 1195 am.setPackageAskScreenCompat(packageName, isChecked); 1196 } else if (buttonView == mEnableCompatibilityCB) { 1197 am.setPackageScreenCompatMode(packageName, isChecked ? 1198 ActivityManager.COMPAT_MODE_ENABLED : ActivityManager.COMPAT_MODE_DISABLED); 1199 } else if (buttonView == mNotificationSwitch) { 1200 if (!isChecked) { 1201 showDialogInner(DLG_DISABLE_NOTIFICATIONS, 0); 1202 } else { 1203 setNotificationsEnabled(true); 1204 } 1205 } 1206 } 1207} 1208 1209