InstalledAppDetails.java revision 4bb075bc4fb415eacb0fe2d7e74f16de2d9c718a
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 android.app.Activity; 20import android.app.ActivityManager; 21import android.app.AlertDialog; 22import android.app.LoaderManager.LoaderCallbacks; 23import android.content.BroadcastReceiver; 24import android.content.ComponentName; 25import android.content.Context; 26import android.content.DialogInterface; 27import android.content.Intent; 28import android.content.Loader; 29import android.content.pm.ApplicationInfo; 30import android.content.pm.PackageInfo; 31import android.content.pm.PackageManager; 32import android.content.pm.PackageManager.NameNotFoundException; 33import android.content.pm.ResolveInfo; 34import android.net.INetworkStatsService; 35import android.net.INetworkStatsSession; 36import android.net.NetworkTemplate; 37import android.net.TrafficStats; 38import android.net.Uri; 39import android.os.AsyncTask; 40import android.os.Bundle; 41import android.os.RemoteException; 42import android.os.ServiceManager; 43import android.os.UserHandle; 44import android.preference.Preference; 45import android.preference.Preference.OnPreferenceClickListener; 46import android.provider.Settings; 47import android.text.format.DateUtils; 48import android.text.format.Formatter; 49import android.view.Menu; 50import android.view.MenuInflater; 51import android.view.MenuItem; 52import android.view.View; 53import android.widget.Button; 54import android.widget.ImageView; 55import android.widget.TextView; 56 57import com.android.settings.DataUsageSummary; 58import com.android.settings.DataUsageSummary.AppItem; 59import com.android.settings.R; 60import com.android.settings.SettingsActivity; 61import com.android.settings.Utils; 62import com.android.settings.applications.ApplicationsState.AppEntry; 63import com.android.settings.net.ChartData; 64import com.android.settings.net.ChartDataLoader; 65import com.android.settings.notification.NotificationAppList; 66import com.android.settings.notification.NotificationAppList.AppRow; 67import com.android.settings.notification.NotificationAppList.Backend; 68 69import java.lang.ref.WeakReference; 70import java.util.ArrayList; 71import java.util.HashSet; 72import java.util.List; 73 74/** 75 * Activity to display application information from Settings. This activity presents 76 * extended information associated with a package like code, data, total size, permissions 77 * used by the application and also the set of default launchable activities. 78 * For system applications, an option to clear user data is displayed only if data size is > 0. 79 * System applications that do not want clear user data do not have this option. 80 * For non-system applications, there is no option to clear data. Instead there is an option to 81 * uninstall the application. 82 */ 83public class InstalledAppDetails extends AppInfoBase 84 implements View.OnClickListener, OnPreferenceClickListener { 85 86 // Menu identifiers 87 public static final int UNINSTALL_ALL_USERS_MENU = 1; 88 89 // Result code identifiers 90 public static final int REQUEST_UNINSTALL = 0; 91 private static final int SUB_INFO_FRAGMENT = 1; 92 93 private static final int LOADER_CHART_DATA = 2; 94 95 private static final int DLG_FORCE_STOP = DLG_BASE + 1; 96 private static final int DLG_DISABLE = DLG_BASE + 2; 97 private static final int DLG_SPECIAL_DISABLE = DLG_BASE + 3; 98 private static final int DLG_FACTORY_RESET = DLG_BASE + 4; 99 100 private static final String KEY_HEADER = "header_view"; 101 private static final String KEY_NOTIFICATION = "notification_settings"; 102 private static final String KEY_STORAGE = "storage_settings"; 103 private static final String KEY_PERMISSION = "permission_settings"; 104 private static final String KEY_DATA = "data_settings"; 105 private static final String KEY_LAUNCH = "preferred_settings"; 106 107 private final HashSet<String> mHomePackages = new HashSet<String>(); 108 109 private boolean mInitialized; 110 private boolean mShowUninstalled; 111 private HeaderPreference mHeader; 112 private Button mUninstallButton; 113 private View mMoreControlButtons; 114 private Button mSpecialDisableButton; 115 private boolean mUpdatedSysApp = false; 116 private TextView mAppVersion; 117 private Button mForceStopButton; 118 private Preference mNotificationPreference; 119 private Preference mStoragePreference; 120 private Preference mPermissionsPreference; 121 private Preference mLaunchPreference; 122 private Preference mDataPreference; 123 124 private boolean mDisableAfterUninstall; 125 // Used for updating notification preference. 126 private final Backend mBackend = new Backend(); 127 128 private ChartData mChartData; 129 private INetworkStatsSession mStatsSession; 130 131 private boolean handleDisableable(Button button) { 132 boolean disableable = false; 133 // Try to prevent the user from bricking their phone 134 // by not allowing disabling of apps signed with the 135 // system cert and any launcher app in the system. 136 if (mHomePackages.contains(mAppEntry.info.packageName) 137 || Utils.isSystemPackage(mPm, mPackageInfo)) { 138 // Disable button for core system applications. 139 button.setText(R.string.disable_text); 140 } else if (mAppEntry.info.enabled) { 141 button.setText(R.string.disable_text); 142 disableable = true; 143 } else { 144 button.setText(R.string.enable_text); 145 disableable = true; 146 } 147 148 return disableable; 149 } 150 151 private void initUninstallButtons() { 152 mUpdatedSysApp = (mAppEntry.info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; 153 final boolean isBundled = (mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0; 154 boolean enabled = true; 155 if (mUpdatedSysApp) { 156 mUninstallButton.setText(R.string.app_factory_reset); 157 boolean showSpecialDisable = false; 158 if (isBundled) { 159 showSpecialDisable = handleDisableable(mSpecialDisableButton); 160 mSpecialDisableButton.setOnClickListener(this); 161 } 162 if (mAppControlRestricted) { 163 showSpecialDisable = false; 164 } 165 mMoreControlButtons.setVisibility(showSpecialDisable ? View.VISIBLE : View.GONE); 166 } else { 167 mMoreControlButtons.setVisibility(View.GONE); 168 if (isBundled) { 169 enabled = handleDisableable(mUninstallButton); 170 } else if ((mPackageInfo.applicationInfo.flags 171 & ApplicationInfo.FLAG_INSTALLED) == 0 172 && mUserManager.getUsers().size() >= 2) { 173 // When we have multiple users, there is a separate menu 174 // to uninstall for all users. 175 mUninstallButton.setText(R.string.uninstall_text); 176 enabled = false; 177 } else { 178 mUninstallButton.setText(R.string.uninstall_text); 179 } 180 } 181 // If this is a device admin, it can't be uninstalled or disabled. 182 // We do this here so the text of the button is still set correctly. 183 if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) { 184 enabled = false; 185 } 186 187 // Home apps need special handling. Bundled ones we don't risk downgrading 188 // because that can interfere with home-key resolution. Furthermore, we 189 // can't allow uninstallation of the only home app, and we don't want to 190 // allow uninstallation of an explicitly preferred one -- the user can go 191 // to Home settings and pick a different one, after which we'll permit 192 // uninstallation of the now-not-default one. 193 if (enabled && mHomePackages.contains(mPackageInfo.packageName)) { 194 if (isBundled) { 195 enabled = false; 196 } else { 197 ArrayList<ResolveInfo> homeActivities = new ArrayList<ResolveInfo>(); 198 ComponentName currentDefaultHome = mPm.getHomeActivities(homeActivities); 199 if (currentDefaultHome == null) { 200 // No preferred default, so permit uninstall only when 201 // there is more than one candidate 202 enabled = (mHomePackages.size() > 1); 203 } else { 204 // There is an explicit default home app -- forbid uninstall of 205 // that one, but permit it for installed-but-inactive ones. 206 enabled = !mPackageInfo.packageName.equals(currentDefaultHome.getPackageName()); 207 } 208 } 209 } 210 211 if (mAppControlRestricted) { 212 enabled = false; 213 } 214 215 mUninstallButton.setEnabled(enabled); 216 if (enabled) { 217 // Register listener 218 mUninstallButton.setOnClickListener(this); 219 } 220 } 221 222 /** Called when the activity is first created. */ 223 @Override 224 public void onCreate(Bundle icicle) { 225 super.onCreate(icicle); 226 227 setHasOptionsMenu(true); 228 addPreferencesFromResource(R.xml.installed_app_details); 229 230 INetworkStatsService statsService = INetworkStatsService.Stub.asInterface( 231 ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); 232 try { 233 mStatsSession = statsService.openSession(); 234 } catch (RemoteException e) { 235 throw new RuntimeException(e); 236 } 237 } 238 239 @Override 240 public void onResume() { 241 super.onResume(); 242 AppItem app = new AppItem(mAppEntry.info.uid); 243 app.addUid(mAppEntry.info.uid); 244 getLoaderManager().restartLoader(LOADER_CHART_DATA, 245 ChartDataLoader.buildArgs(NetworkTemplate.buildTemplateMobileWildcard(), app), 246 mDataCallbacks); 247 } 248 249 @Override 250 public void onPause() { 251 getLoaderManager().destroyLoader(LOADER_CHART_DATA); 252 super.onPause(); 253 } 254 255 @Override 256 public void onDestroy() { 257 TrafficStats.closeQuietly(mStatsSession); 258 259 super.onDestroy(); 260 } 261 262 public void onActivityCreated(Bundle savedInstanceState) { 263 super.onActivityCreated(savedInstanceState); 264 handleHeader(); 265 266 mNotificationPreference = findPreference(KEY_NOTIFICATION); 267 mNotificationPreference.setOnPreferenceClickListener(this); 268 mStoragePreference = findPreference(KEY_STORAGE); 269 mStoragePreference.setOnPreferenceClickListener(this); 270 mPermissionsPreference = findPreference(KEY_PERMISSION); 271 mPermissionsPreference.setOnPreferenceClickListener(this); 272 mLaunchPreference = findPreference(KEY_LAUNCH); 273 mLaunchPreference.setOnPreferenceClickListener(this); 274 mDataPreference = findPreference(KEY_DATA); 275 mDataPreference.setOnPreferenceClickListener(this); 276 } 277 278 private void handleHeader() { 279 mHeader = (HeaderPreference) findPreference(KEY_HEADER); 280 281 // Get Control button panel 282 View btnPanel = mHeader.findViewById(R.id.control_buttons_panel); 283 mForceStopButton = (Button) btnPanel.findViewById(R.id.right_button); 284 mForceStopButton.setText(R.string.force_stop); 285 mUninstallButton = (Button) btnPanel.findViewById(R.id.left_button); 286 mForceStopButton.setEnabled(false); 287 288 // Get More Control button panel 289 mMoreControlButtons = mHeader.findViewById(R.id.more_control_buttons_panel); 290 mMoreControlButtons.findViewById(R.id.right_button).setVisibility(View.INVISIBLE); 291 mSpecialDisableButton = (Button) mMoreControlButtons.findViewById(R.id.left_button); 292 mMoreControlButtons.setVisibility(View.GONE); 293 } 294 295 @Override 296 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 297 menu.add(0, UNINSTALL_ALL_USERS_MENU, 1, R.string.uninstall_all_users_text) 298 .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); 299 } 300 301 @Override 302 public void onPrepareOptionsMenu(Menu menu) { 303 boolean showIt = true; 304 if (mUpdatedSysApp) { 305 showIt = false; 306 } else if (mAppEntry == null) { 307 showIt = false; 308 } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 309 showIt = false; 310 } else if (mPackageInfo == null || mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) { 311 showIt = false; 312 } else if (UserHandle.myUserId() != 0) { 313 showIt = false; 314 } else if (mUserManager.getUsers().size() < 2) { 315 showIt = false; 316 } 317 menu.findItem(UNINSTALL_ALL_USERS_MENU).setVisible(showIt); 318 } 319 320 @Override 321 public boolean onOptionsItemSelected(MenuItem item) { 322 int menuId = item.getItemId(); 323 if (menuId == UNINSTALL_ALL_USERS_MENU) { 324 uninstallPkg(mAppEntry.info.packageName, true, false); 325 return true; 326 } 327 return false; 328 } 329 330 @Override 331 public void onActivityResult(int requestCode, int resultCode, Intent data) { 332 super.onActivityResult(requestCode, resultCode, data); 333 if (requestCode == REQUEST_UNINSTALL) { 334 if (mDisableAfterUninstall) { 335 mDisableAfterUninstall = false; 336 try { 337 ApplicationInfo ainfo = getActivity().getPackageManager().getApplicationInfo( 338 mAppEntry.info.packageName, PackageManager.GET_UNINSTALLED_PACKAGES 339 | PackageManager.GET_DISABLED_COMPONENTS); 340 if ((ainfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0) { 341 new DisableChanger(this, mAppEntry.info, 342 PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) 343 .execute((Object)null); 344 } 345 } catch (NameNotFoundException e) { 346 } 347 } 348 if (!refreshUi()) { 349 setIntentAndFinish(true, true); 350 } 351 } 352 } 353 354 // Utility method to set application label and icon. 355 private void setAppLabelAndIcon(PackageInfo pkgInfo) { 356 final View appSnippet = mHeader.findViewById(R.id.app_snippet); 357 appSnippet.setPaddingRelative(0, appSnippet.getPaddingTop(), 0, 358 appSnippet.getPaddingBottom()); 359 360 ImageView icon = (ImageView) appSnippet.findViewById(R.id.app_icon); 361 mState.ensureIcon(mAppEntry); 362 icon.setImageDrawable(mAppEntry.icon); 363 // Set application name. 364 TextView label = (TextView) appSnippet.findViewById(R.id.app_name); 365 label.setText(mAppEntry.label); 366 // Version number of application 367 mAppVersion = (TextView) appSnippet.findViewById(R.id.app_size); 368 369 if (pkgInfo != null && pkgInfo.versionName != null) { 370 mAppVersion.setVisibility(View.VISIBLE); 371 mAppVersion.setText(getActivity().getString(R.string.version_text, 372 String.valueOf(pkgInfo.versionName))); 373 } else { 374 mAppVersion.setVisibility(View.INVISIBLE); 375 } 376 } 377 378 private boolean signaturesMatch(String pkg1, String pkg2) { 379 if (pkg1 != null && pkg2 != null) { 380 try { 381 final int match = mPm.checkSignatures(pkg1, pkg2); 382 if (match >= PackageManager.SIGNATURE_MATCH) { 383 return true; 384 } 385 } catch (Exception e) { 386 // e.g. named alternate package not found during lookup; 387 // this is an expected case sometimes 388 } 389 } 390 return false; 391 } 392 393 @Override 394 protected boolean refreshUi() { 395 retrieveAppEntry(); 396 if (mAppEntry == null) { 397 return false; // onCreate must have failed, make sure to exit 398 } 399 400 if (mPackageInfo == null) { 401 return false; // onCreate must have failed, make sure to exit 402 } 403 404 // Get list of "home" apps and trace through any meta-data references 405 List<ResolveInfo> homeActivities = new ArrayList<ResolveInfo>(); 406 mPm.getHomeActivities(homeActivities); 407 mHomePackages.clear(); 408 for (int i = 0; i< homeActivities.size(); i++) { 409 ResolveInfo ri = homeActivities.get(i); 410 final String activityPkg = ri.activityInfo.packageName; 411 mHomePackages.add(activityPkg); 412 413 // Also make sure to include anything proxying for the home app 414 final Bundle metadata = ri.activityInfo.metaData; 415 if (metadata != null) { 416 final String metaPkg = metadata.getString(ActivityManager.META_HOME_ALTERNATE); 417 if (signaturesMatch(metaPkg, activityPkg)) { 418 mHomePackages.add(metaPkg); 419 } 420 } 421 } 422 423 checkForceStop(); 424 setAppLabelAndIcon(mPackageInfo); 425 initUninstallButtons(); 426 427 // Update the preference summaries. 428 Activity context = getActivity(); 429 mStoragePreference.setSummary(AppStorageSettings.getSummary(mAppEntry, context)); 430 mPermissionsPreference.setSummary(AppPermissionSettings.getSummary(mAppEntry, context)); 431 mLaunchPreference.setSummary(AppLaunchSettings.getSummary(mAppEntry, mUsbManager, 432 mPm, context)); 433 mNotificationPreference.setSummary(getNotificationSummary(mAppEntry, context, 434 mBackend)); 435 mDataPreference.setSummary(getDataSummary()); 436 437 if (!mInitialized) { 438 // First time init: are we displaying an uninstalled app? 439 mInitialized = true; 440 mShowUninstalled = (mAppEntry.info.flags&ApplicationInfo.FLAG_INSTALLED) == 0; 441 } else { 442 // All other times: if the app no longer exists then we want 443 // to go away. 444 try { 445 ApplicationInfo ainfo = context.getPackageManager().getApplicationInfo( 446 mAppEntry.info.packageName, PackageManager.GET_UNINSTALLED_PACKAGES 447 | PackageManager.GET_DISABLED_COMPONENTS); 448 if (!mShowUninstalled) { 449 // If we did not start out with the app uninstalled, then 450 // it transitioning to the uninstalled state for the current 451 // user means we should go away as well. 452 return (ainfo.flags&ApplicationInfo.FLAG_INSTALLED) != 0; 453 } 454 } catch (NameNotFoundException e) { 455 return false; 456 } 457 } 458 459 return true; 460 } 461 462 private CharSequence getDataSummary() { 463 if (mChartData != null) { 464 long totalBytes = mChartData.detail.getTotalBytes(); 465 Context context = getActivity(); 466 return getString(R.string.data_summary_format, 467 Formatter.formatFileSize(context, totalBytes), 468 DateUtils.formatDateTime(context, mChartData.detail.getStart(), 469 DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH)); 470 } 471 return getString(R.string.computing_size); 472 } 473 474 @Override 475 protected AlertDialog createDialog(int id, int errorCode) { 476 switch (id) { 477 case DLG_DISABLE: 478 return new AlertDialog.Builder(getActivity()) 479 .setTitle(getActivity().getText(R.string.app_disable_dlg_title)) 480 .setMessage(getActivity().getText(R.string.app_disable_dlg_text)) 481 .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() { 482 public void onClick(DialogInterface dialog, int which) { 483 // Disable the app 484 new DisableChanger(InstalledAppDetails.this, mAppEntry.info, 485 PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) 486 .execute((Object)null); 487 } 488 }) 489 .setNegativeButton(R.string.dlg_cancel, null) 490 .create(); 491 case DLG_SPECIAL_DISABLE: 492 return new AlertDialog.Builder(getActivity()) 493 .setTitle(getActivity().getText(R.string.app_special_disable_dlg_title)) 494 .setMessage(getActivity().getText(R.string.app_special_disable_dlg_text)) 495 .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() { 496 public void onClick(DialogInterface dialog, int which) { 497 // Clear user data here 498 uninstallPkg(mAppEntry.info.packageName, 499 false, true); 500 } 501 }) 502 .setNegativeButton(R.string.dlg_cancel, null) 503 .create(); 504 case DLG_FORCE_STOP: 505 return new AlertDialog.Builder(getActivity()) 506 .setTitle(getActivity().getText(R.string.force_stop_dlg_title)) 507 .setMessage(getActivity().getText(R.string.force_stop_dlg_text)) 508 .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() { 509 public void onClick(DialogInterface dialog, int which) { 510 // Force stop 511 forceStopPackage(mAppEntry.info.packageName); 512 } 513 }) 514 .setNegativeButton(R.string.dlg_cancel, null) 515 .create(); 516 case DLG_FACTORY_RESET: 517 return new AlertDialog.Builder(getActivity()) 518 .setTitle(getActivity().getText(R.string.app_factory_reset_dlg_title)) 519 .setMessage(getActivity().getText(R.string.app_factory_reset_dlg_text)) 520 .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() { 521 public void onClick(DialogInterface dialog, int which) { 522 // Clear user data here 523 uninstallPkg(mAppEntry.info.packageName, 524 false, false); 525 } 526 }) 527 .setNegativeButton(R.string.dlg_cancel, null) 528 .create(); 529 } 530 return null; 531 } 532 533 private void uninstallPkg(String packageName, boolean allUsers, boolean andDisable) { 534 // Create new intent to launch Uninstaller activity 535 Uri packageURI = Uri.parse("package:"+packageName); 536 Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageURI); 537 uninstallIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, allUsers); 538 startActivityForResult(uninstallIntent, REQUEST_UNINSTALL); 539 mDisableAfterUninstall = andDisable; 540 } 541 542 private void forceStopPackage(String pkgName) { 543 ActivityManager am = (ActivityManager)getActivity().getSystemService( 544 Context.ACTIVITY_SERVICE); 545 am.forceStopPackage(pkgName); 546 int userId = UserHandle.getUserId(mAppEntry.info.uid); 547 mState.invalidatePackage(pkgName, userId); 548 ApplicationsState.AppEntry newEnt = mState.getEntry(pkgName, userId); 549 if (newEnt != null) { 550 mAppEntry = newEnt; 551 } 552 checkForceStop(); 553 } 554 555 private void updateForceStopButton(boolean enabled) { 556 if (mAppControlRestricted) { 557 mForceStopButton.setEnabled(false); 558 } else { 559 mForceStopButton.setEnabled(enabled); 560 mForceStopButton.setOnClickListener(InstalledAppDetails.this); 561 } 562 } 563 564 private void checkForceStop() { 565 if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) { 566 // User can't force stop device admin. 567 updateForceStopButton(false); 568 } else if ((mAppEntry.info.flags&ApplicationInfo.FLAG_STOPPED) == 0) { 569 // If the app isn't explicitly stopped, then always show the 570 // force stop button. 571 updateForceStopButton(true); 572 } else { 573 Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART, 574 Uri.fromParts("package", mAppEntry.info.packageName, null)); 575 intent.putExtra(Intent.EXTRA_PACKAGES, new String[] { mAppEntry.info.packageName }); 576 intent.putExtra(Intent.EXTRA_UID, mAppEntry.info.uid); 577 intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(mAppEntry.info.uid)); 578 getActivity().sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null, 579 mCheckKillProcessesReceiver, null, Activity.RESULT_CANCELED, null, null); 580 } 581 } 582 583 private void startAppInfoFragment(Class<? extends AppInfoBase> fragment, CharSequence title) { 584 // start new fragment to display extended information 585 Bundle args = new Bundle(); 586 args.putString(InstalledAppDetails.ARG_PACKAGE_NAME, mAppEntry.info.packageName); 587 588 SettingsActivity sa = (SettingsActivity) getActivity(); 589 sa.startPreferencePanel(fragment.getName(), args, -1, title, this, SUB_INFO_FRAGMENT); 590 } 591 592 private void startNotifications() { 593 // start new fragment to display extended information 594 getActivity().startActivity(new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS) 595 .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) 596 .putExtra(Settings.EXTRA_APP_PACKAGE, mAppEntry.info.packageName) 597 .putExtra(Settings.EXTRA_APP_UID, mAppEntry.info.uid)); 598 } 599 600 /* 601 * Method implementing functionality of buttons clicked 602 * @see android.view.View.OnClickListener#onClick(android.view.View) 603 */ 604 public void onClick(View v) { 605 String packageName = mAppEntry.info.packageName; 606 if(v == mUninstallButton) { 607 if (mUpdatedSysApp) { 608 showDialogInner(DLG_FACTORY_RESET, 0); 609 } else { 610 if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 611 if (mAppEntry.info.enabled) { 612 showDialogInner(DLG_DISABLE, 0); 613 } else { 614 new DisableChanger(this, mAppEntry.info, 615 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) 616 .execute((Object)null); 617 } 618 } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_INSTALLED) == 0) { 619 uninstallPkg(packageName, true, false); 620 } else { 621 uninstallPkg(packageName, false, false); 622 } 623 } 624 } else if(v == mSpecialDisableButton) { 625 showDialogInner(DLG_SPECIAL_DISABLE, 0); 626 } else if (v == mForceStopButton) { 627 showDialogInner(DLG_FORCE_STOP, 0); 628 //forceStopPackage(mAppInfo.packageName); 629 } 630 } 631 632 @Override 633 public boolean onPreferenceClick(Preference preference) { 634 if (preference == mStoragePreference) { 635 startAppInfoFragment(AppStorageSettings.class, mStoragePreference.getTitle()); 636 } else if (preference == mNotificationPreference) { 637 startNotifications(); 638 } else if (preference == mPermissionsPreference) { 639 startAppInfoFragment(AppPermissionSettings.class, mPermissionsPreference.getTitle()); 640 } else if (preference == mLaunchPreference) { 641 startAppInfoFragment(AppLaunchSettings.class, mLaunchPreference.getTitle()); 642 } else if (preference == mDataPreference) { 643 Bundle args = new Bundle(); 644 args.putString(DataUsageSummary.EXTRA_SHOW_APP_IMMEDIATE_PKG, 645 mAppEntry.info.packageName); 646 647 SettingsActivity sa = (SettingsActivity) getActivity(); 648 sa.startPreferencePanel(DataUsageSummary.class.getName(), args, -1, 649 getString(R.string.app_data_usage), this, SUB_INFO_FRAGMENT); 650 } else { 651 return false; 652 } 653 return true; 654 } 655 656 public static CharSequence getNotificationSummary(AppEntry appEntry, Context context) { 657 return getNotificationSummary(appEntry, context, new Backend()); 658 } 659 660 public static CharSequence getNotificationSummary(AppEntry appEntry, Context context, 661 Backend backend) { 662 AppRow appRow = NotificationAppList.loadAppRow(context.getPackageManager(), appEntry.info, 663 backend); 664 if (appRow.banned) { 665 return context.getString(R.string.notifications_disabled); 666 } else if (appRow.priority) { 667 if (appRow.sensitive) { 668 return context.getString(R.string.notifications_priority_sensitive); 669 } 670 return context.getString(R.string.notifications_priority); 671 } else if (appRow.sensitive) { 672 return context.getString(R.string.notifications_sensitive); 673 } 674 return context.getString(R.string.notifications_enabled); 675 } 676 677 static class DisableChanger extends AsyncTask<Object, Object, Object> { 678 final PackageManager mPm; 679 final WeakReference<InstalledAppDetails> mActivity; 680 final ApplicationInfo mInfo; 681 final int mState; 682 683 DisableChanger(InstalledAppDetails activity, ApplicationInfo info, int state) { 684 mPm = activity.mPm; 685 mActivity = new WeakReference<InstalledAppDetails>(activity); 686 mInfo = info; 687 mState = state; 688 } 689 690 @Override 691 protected Object doInBackground(Object... params) { 692 mPm.setApplicationEnabledSetting(mInfo.packageName, mState, 0); 693 return null; 694 } 695 } 696 697 private final LoaderCallbacks<ChartData> mDataCallbacks = new LoaderCallbacks<ChartData>() { 698 699 @Override 700 public Loader<ChartData> onCreateLoader(int id, Bundle args) { 701 return new ChartDataLoader(getActivity(), mStatsSession, args); 702 } 703 704 @Override 705 public void onLoadFinished(Loader<ChartData> loader, ChartData data) { 706 mChartData = data; 707 mDataPreference.setSummary(getDataSummary()); 708 } 709 710 @Override 711 public void onLoaderReset(Loader<ChartData> loader) { 712 mChartData = null; 713 mDataPreference.setSummary(getDataSummary()); 714 } 715 }; 716 717 private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() { 718 @Override 719 public void onReceive(Context context, Intent intent) { 720 updateForceStopButton(getResultCode() != Activity.RESULT_CANCELED); 721 } 722 }; 723} 724 725 726