InstalledAppDetails.java revision 25f9e326ab65e5298737721e959b22aea68148f1
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.ActivityNotFoundException; 24import android.content.BroadcastReceiver; 25import android.content.ComponentName; 26import android.content.Context; 27import android.content.DialogInterface; 28import android.content.Intent; 29import android.content.Loader; 30import android.content.pm.ApplicationInfo; 31import android.content.pm.PackageInfo; 32import android.content.pm.PackageManager; 33import android.content.pm.PackageManager.NameNotFoundException; 34import android.content.pm.ResolveInfo; 35import android.net.INetworkStatsService; 36import android.net.INetworkStatsSession; 37import android.net.NetworkTemplate; 38import android.net.TrafficStats; 39import android.net.Uri; 40import android.os.AsyncTask; 41import android.os.Bundle; 42import android.os.RemoteException; 43import android.os.ServiceManager; 44import android.os.UserHandle; 45import android.preference.Preference; 46import android.preference.Preference.OnPreferenceClickListener; 47import android.provider.Settings; 48import android.text.format.DateUtils; 49import android.text.format.Formatter; 50import android.util.Log; 51import android.view.Menu; 52import android.view.MenuInflater; 53import android.view.MenuItem; 54import android.view.View; 55import android.widget.Button; 56import android.widget.ImageView; 57import android.widget.TextView; 58 59import com.android.internal.logging.MetricsLogger; 60import com.android.settings.DataUsageSummary; 61import com.android.settings.DataUsageSummary.AppItem; 62import com.android.settings.R; 63import com.android.settings.SettingsActivity; 64import com.android.settings.Utils; 65import com.android.settings.applications.ApplicationsState.AppEntry; 66import com.android.settings.net.ChartData; 67import com.android.settings.net.ChartDataLoader; 68import com.android.settings.notification.NotificationBackend; 69import com.android.settings.notification.NotificationBackend.AppRow; 70 71import java.lang.ref.WeakReference; 72import java.util.ArrayList; 73import java.util.HashSet; 74import java.util.List; 75 76/** 77 * Activity to display application information from Settings. This activity presents 78 * extended information associated with a package like code, data, total size, permissions 79 * used by the application and also the set of default launchable activities. 80 * For system applications, an option to clear user data is displayed only if data size is > 0. 81 * System applications that do not want clear user data do not have this option. 82 * For non-system applications, there is no option to clear data. Instead there is an option to 83 * uninstall the application. 84 */ 85public class InstalledAppDetails extends AppInfoBase 86 implements View.OnClickListener, OnPreferenceClickListener { 87 88 private static final String LOG_TAG = "InstalledAppDetails"; 89 90 // Menu identifiers 91 public static final int UNINSTALL_ALL_USERS_MENU = 1; 92 public static final int UNINSTALL_UPDATES = 2; 93 94 // Result code identifiers 95 public static final int REQUEST_UNINSTALL = 0; 96 private static final int SUB_INFO_FRAGMENT = 1; 97 98 private static final int LOADER_CHART_DATA = 2; 99 100 private static final int DLG_FORCE_STOP = DLG_BASE + 1; 101 private static final int DLG_DISABLE = DLG_BASE + 2; 102 private static final int DLG_SPECIAL_DISABLE = DLG_BASE + 3; 103 private static final int DLG_FACTORY_RESET = DLG_BASE + 4; 104 105 private static final String KEY_HEADER = "header_view"; 106 private static final String KEY_NOTIFICATION = "notification_settings"; 107 private static final String KEY_STORAGE = "storage_settings"; 108 private static final String KEY_PERMISSION = "permission_settings"; 109 private static final String KEY_DATA = "data_settings"; 110 private static final String KEY_LAUNCH = "preferred_settings"; 111 112 private final HashSet<String> mHomePackages = new HashSet<String>(); 113 114 private boolean mInitialized; 115 private boolean mShowUninstalled; 116 private LayoutPreference mHeader; 117 private Button mUninstallButton; 118 private boolean mUpdatedSysApp = false; 119 private TextView mAppVersion; 120 private Button mForceStopButton; 121 private Preference mNotificationPreference; 122 private Preference mStoragePreference; 123 private Preference mPermissionsPreference; 124 private Preference mLaunchPreference; 125 private Preference mDataPreference; 126 127 private boolean mDisableAfterUninstall; 128 // Used for updating notification preference. 129 private final NotificationBackend mBackend = new NotificationBackend(); 130 131 private ChartData mChartData; 132 private INetworkStatsSession mStatsSession; 133 134 private boolean handleDisableable(Button button) { 135 boolean disableable = false; 136 // Try to prevent the user from bricking their phone 137 // by not allowing disabling of apps signed with the 138 // system cert and any launcher app in the system. 139 if (mHomePackages.contains(mAppEntry.info.packageName) 140 || Utils.isSystemPackage(mPm, mPackageInfo)) { 141 // Disable button for core system applications. 142 button.setText(R.string.disable_text); 143 } else if (mAppEntry.info.enabled) { 144 button.setText(R.string.disable_text); 145 disableable = true; 146 } else { 147 button.setText(R.string.enable_text); 148 disableable = true; 149 } 150 151 return disableable; 152 } 153 154 private void initUninstallButtons() { 155 final boolean isBundled = (mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0; 156 boolean enabled = true; 157 if (isBundled) { 158 enabled = handleDisableable(mUninstallButton); 159 } else { 160 if ((mPackageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) == 0 161 && mUserManager.getUsers().size() >= 2) { 162 // When we have multiple users, there is a separate menu 163 // to uninstall for all users. 164 enabled = false; 165 } 166 mUninstallButton.setText(R.string.uninstall_text); 167 } 168 // If this is a device admin, it can't be uninstalled or disabled. 169 // We do this here so the text of the button is still set correctly. 170 if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) { 171 enabled = false; 172 } 173 174 // Home apps need special handling. Bundled ones we don't risk downgrading 175 // because that can interfere with home-key resolution. Furthermore, we 176 // can't allow uninstallation of the only home app, and we don't want to 177 // allow uninstallation of an explicitly preferred one -- the user can go 178 // to Home settings and pick a different one, after which we'll permit 179 // uninstallation of the now-not-default one. 180 if (enabled && mHomePackages.contains(mPackageInfo.packageName)) { 181 if (isBundled) { 182 enabled = false; 183 } else { 184 ArrayList<ResolveInfo> homeActivities = new ArrayList<ResolveInfo>(); 185 ComponentName currentDefaultHome = mPm.getHomeActivities(homeActivities); 186 if (currentDefaultHome == null) { 187 // No preferred default, so permit uninstall only when 188 // there is more than one candidate 189 enabled = (mHomePackages.size() > 1); 190 } else { 191 // There is an explicit default home app -- forbid uninstall of 192 // that one, but permit it for installed-but-inactive ones. 193 enabled = !mPackageInfo.packageName.equals(currentDefaultHome.getPackageName()); 194 } 195 } 196 } 197 198 if (mAppControlRestricted) { 199 enabled = false; 200 } 201 202 mUninstallButton.setEnabled(enabled); 203 if (enabled) { 204 // Register listener 205 mUninstallButton.setOnClickListener(this); 206 } 207 } 208 209 /** Called when the activity is first created. */ 210 @Override 211 public void onCreate(Bundle icicle) { 212 super.onCreate(icicle); 213 214 setHasOptionsMenu(true); 215 addPreferencesFromResource(R.xml.installed_app_details); 216 217 INetworkStatsService statsService = INetworkStatsService.Stub.asInterface( 218 ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); 219 try { 220 mStatsSession = statsService.openSession(); 221 } catch (RemoteException e) { 222 throw new RuntimeException(e); 223 } 224 } 225 226 @Override 227 protected int getMetricsCategory() { 228 return MetricsLogger.APPLICATIONS_INSTALLED_APP_DETAILS; 229 } 230 231 @Override 232 public void onResume() { 233 super.onResume(); 234 AppItem app = new AppItem(mAppEntry.info.uid); 235 app.addUid(mAppEntry.info.uid); 236 getLoaderManager().restartLoader(LOADER_CHART_DATA, 237 ChartDataLoader.buildArgs(NetworkTemplate.buildTemplateMobileWildcard(), app), 238 mDataCallbacks); 239 } 240 241 @Override 242 public void onPause() { 243 getLoaderManager().destroyLoader(LOADER_CHART_DATA); 244 super.onPause(); 245 } 246 247 @Override 248 public void onDestroy() { 249 TrafficStats.closeQuietly(mStatsSession); 250 251 super.onDestroy(); 252 } 253 254 public void onActivityCreated(Bundle savedInstanceState) { 255 super.onActivityCreated(savedInstanceState); 256 handleHeader(); 257 258 mNotificationPreference = findPreference(KEY_NOTIFICATION); 259 mNotificationPreference.setOnPreferenceClickListener(this); 260 mStoragePreference = findPreference(KEY_STORAGE); 261 mStoragePreference.setOnPreferenceClickListener(this); 262 mPermissionsPreference = findPreference(KEY_PERMISSION); 263 mPermissionsPreference.setOnPreferenceClickListener(this); 264 mDataPreference = findPreference(KEY_DATA); 265 mDataPreference.setOnPreferenceClickListener(this); 266 267 mLaunchPreference = findPreference(KEY_LAUNCH); 268 if ((mAppEntry.info.flags&ApplicationInfo.FLAG_INSTALLED) == 0) { 269 mLaunchPreference.setEnabled(false); 270 } else if (!mAppEntry.info.enabled) { 271 mLaunchPreference.setEnabled(false); 272 } else { 273 mLaunchPreference.setOnPreferenceClickListener(this); 274 } 275 } 276 277 private void handleHeader() { 278 mHeader = (LayoutPreference) findPreference(KEY_HEADER); 279 280 // Get Control button panel 281 View btnPanel = mHeader.findViewById(R.id.control_buttons_panel); 282 mForceStopButton = (Button) btnPanel.findViewById(R.id.right_button); 283 mForceStopButton.setText(R.string.force_stop); 284 mUninstallButton = (Button) btnPanel.findViewById(R.id.left_button); 285 mForceStopButton.setEnabled(false); 286 } 287 288 @Override 289 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 290 menu.add(0, UNINSTALL_UPDATES, 0, R.string.app_factory_reset) 291 .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); 292 menu.add(0, UNINSTALL_ALL_USERS_MENU, 1, R.string.uninstall_all_users_text) 293 .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); 294 } 295 296 @Override 297 public void onPrepareOptionsMenu(Menu menu) { 298 boolean showIt = true; 299 if (mUpdatedSysApp) { 300 showIt = false; 301 } else if (mAppEntry == null) { 302 showIt = false; 303 } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 304 showIt = false; 305 } else if (mPackageInfo == null || mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) { 306 showIt = false; 307 } else if (UserHandle.myUserId() != 0) { 308 showIt = false; 309 } else if (mUserManager.getUsers().size() < 2) { 310 showIt = false; 311 } 312 menu.findItem(UNINSTALL_ALL_USERS_MENU).setVisible(showIt); 313 mUpdatedSysApp = (mAppEntry.info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; 314 menu.findItem(UNINSTALL_UPDATES).setVisible(mUpdatedSysApp && !mAppControlRestricted); 315 } 316 317 @Override 318 public boolean onOptionsItemSelected(MenuItem item) { 319 switch (item.getItemId()) { 320 case UNINSTALL_ALL_USERS_MENU: 321 uninstallPkg(mAppEntry.info.packageName, true, false); 322 return true; 323 case UNINSTALL_UPDATES: 324 showDialogInner(DLG_FACTORY_RESET, 0); 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_summary); 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(Utils.getLaunchByDeafaultSummary(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 startManagePermissionsActivity() { 584 // start new activity to manage app permissions 585 Intent intent = new Intent(Intent.ACTION_MANAGE_APP_PERMISSIONS); 586 intent.putExtra(Intent.EXTRA_PACKAGE_NAME, mAppEntry.info.packageName); 587 try { 588 startActivity(intent); 589 } catch (ActivityNotFoundException e) { 590 Log.w(LOG_TAG, "No app can handle android.intent.action.MANAGE_APP_PERMISSIONS"); 591 } 592 } 593 594 private void startAppInfoFragment(Class<? extends AppInfoBase> fragment, CharSequence title) { 595 // start new fragment to display extended information 596 Bundle args = new Bundle(); 597 args.putString(InstalledAppDetails.ARG_PACKAGE_NAME, mAppEntry.info.packageName); 598 599 SettingsActivity sa = (SettingsActivity) getActivity(); 600 sa.startPreferencePanel(fragment.getName(), args, -1, title, this, SUB_INFO_FRAGMENT); 601 } 602 603 private void startNotifications() { 604 // start new fragment to display extended information 605 getActivity().startActivity(new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS) 606 .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) 607 .putExtra(Settings.EXTRA_APP_PACKAGE, mAppEntry.info.packageName) 608 .putExtra(Settings.EXTRA_APP_UID, mAppEntry.info.uid)); 609 } 610 611 /* 612 * Method implementing functionality of buttons clicked 613 * @see android.view.View.OnClickListener#onClick(android.view.View) 614 */ 615 public void onClick(View v) { 616 String packageName = mAppEntry.info.packageName; 617 if(v == mUninstallButton) { 618 if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 619 if (mAppEntry.info.enabled) { 620 if (mUpdatedSysApp) { 621 showDialogInner(DLG_SPECIAL_DISABLE, 0); 622 } else { 623 showDialogInner(DLG_DISABLE, 0); 624 } 625 } else { 626 new DisableChanger(this, mAppEntry.info, 627 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) 628 .execute((Object) null); 629 } 630 } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_INSTALLED) == 0) { 631 uninstallPkg(packageName, true, false); 632 } else { 633 uninstallPkg(packageName, false, false); 634 } 635 } else if (v == mForceStopButton) { 636 showDialogInner(DLG_FORCE_STOP, 0); 637 //forceStopPackage(mAppInfo.packageName); 638 } 639 } 640 641 @Override 642 public boolean onPreferenceClick(Preference preference) { 643 if (preference == mStoragePreference) { 644 startAppInfoFragment(AppStorageSettings.class, mStoragePreference.getTitle()); 645 } else if (preference == mNotificationPreference) { 646 startNotifications(); 647 } else if (preference == mPermissionsPreference) { 648 startManagePermissionsActivity(); 649 } else if (preference == mLaunchPreference) { 650 startAppInfoFragment(AppLaunchSettings.class, mLaunchPreference.getTitle()); 651 } else if (preference == mDataPreference) { 652 Bundle args = new Bundle(); 653 args.putString(DataUsageSummary.EXTRA_SHOW_APP_IMMEDIATE_PKG, 654 mAppEntry.info.packageName); 655 656 SettingsActivity sa = (SettingsActivity) getActivity(); 657 sa.startPreferencePanel(DataUsageSummary.class.getName(), args, -1, 658 getString(R.string.app_data_usage), this, SUB_INFO_FRAGMENT); 659 } else { 660 return false; 661 } 662 return true; 663 } 664 665 public static CharSequence getNotificationSummary(AppEntry appEntry, Context context) { 666 return getNotificationSummary(appEntry, context, new NotificationBackend()); 667 } 668 669 public static CharSequence getNotificationSummary(AppEntry appEntry, Context context, 670 NotificationBackend backend) { 671 AppRow appRow = backend.loadAppRow(context.getPackageManager(), appEntry.info); 672 return getNotificationSummary(appRow, context); 673 } 674 675 public static CharSequence getNotificationSummary(AppRow appRow, Context context) { 676 if (appRow.banned) { 677 return context.getString(R.string.notifications_disabled); 678 } 679 ArrayList<CharSequence> notifSummary = new ArrayList<>(); 680 if (appRow.priority) { 681 notifSummary.add(context.getString(R.string.notifications_priority)); 682 } 683 if (appRow.sensitive) { 684 notifSummary.add(context.getString(R.string.notifications_sensitive)); 685 } 686 if (!appRow.peekable) { 687 notifSummary.add(context.getString(R.string.notifications_no_peeking)); 688 } 689 switch (notifSummary.size()) { 690 case 3: 691 return context.getString(R.string.notifications_three_items, 692 notifSummary.get(0), notifSummary.get(1), notifSummary.get(2)); 693 case 2: 694 return context.getString(R.string.notifications_two_items, 695 notifSummary.get(0), notifSummary.get(1)); 696 case 1: 697 return notifSummary.get(0); 698 default: 699 return context.getString(R.string.notifications_enabled); 700 } 701 } 702 703 static class DisableChanger extends AsyncTask<Object, Object, Object> { 704 final PackageManager mPm; 705 final WeakReference<InstalledAppDetails> mActivity; 706 final ApplicationInfo mInfo; 707 final int mState; 708 709 DisableChanger(InstalledAppDetails activity, ApplicationInfo info, int state) { 710 mPm = activity.mPm; 711 mActivity = new WeakReference<InstalledAppDetails>(activity); 712 mInfo = info; 713 mState = state; 714 } 715 716 @Override 717 protected Object doInBackground(Object... params) { 718 mPm.setApplicationEnabledSetting(mInfo.packageName, mState, 0); 719 return null; 720 } 721 } 722 723 private final LoaderCallbacks<ChartData> mDataCallbacks = new LoaderCallbacks<ChartData>() { 724 725 @Override 726 public Loader<ChartData> onCreateLoader(int id, Bundle args) { 727 return new ChartDataLoader(getActivity(), mStatsSession, args); 728 } 729 730 @Override 731 public void onLoadFinished(Loader<ChartData> loader, ChartData data) { 732 mChartData = data; 733 mDataPreference.setSummary(getDataSummary()); 734 } 735 736 @Override 737 public void onLoaderReset(Loader<ChartData> loader) { 738 mChartData = null; 739 mDataPreference.setSummary(getDataSummary()); 740 } 741 }; 742 743 private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() { 744 @Override 745 public void onReceive(Context context, Intent intent) { 746 updateForceStopButton(getResultCode() != Activity.RESULT_CANCELED); 747 } 748 }; 749} 750 751 752