1 /* 2 * Copyright (C) 2017 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 17 package com.android.settings.applications.appinfo; 18 19 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; 20 21 import android.app.Activity; 22 import android.app.admin.DevicePolicyManager; 23 import android.app.settings.SettingsEnums; 24 import android.content.BroadcastReceiver; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.IntentFilter; 28 import android.content.pm.ApplicationInfo; 29 import android.content.pm.PackageInfo; 30 import android.content.pm.PackageManager; 31 import android.content.pm.PackageManager.NameNotFoundException; 32 import android.content.pm.UserInfo; 33 import android.net.Uri; 34 import android.os.Bundle; 35 import android.os.UserHandle; 36 import android.os.UserManager; 37 import android.text.TextUtils; 38 import android.util.Log; 39 import android.view.Menu; 40 import android.view.MenuInflater; 41 import android.view.MenuItem; 42 43 import androidx.annotation.VisibleForTesting; 44 45 import com.android.settings.R; 46 import com.android.settings.SettingsActivity; 47 import com.android.settings.SettingsPreferenceFragment; 48 import com.android.settings.applications.manageapplications.ManageApplications; 49 import com.android.settings.applications.specialaccess.interactacrossprofiles.InteractAcrossProfilesDetailsPreferenceController; 50 import com.android.settings.applications.specialaccess.pictureinpicture.PictureInPictureDetailPreferenceController; 51 import com.android.settings.core.SubSettingLauncher; 52 import com.android.settings.dashboard.DashboardFragment; 53 import com.android.settingslib.RestrictedLockUtilsInternal; 54 import com.android.settingslib.applications.AppUtils; 55 import com.android.settingslib.applications.ApplicationsState; 56 import com.android.settingslib.applications.ApplicationsState.AppEntry; 57 import com.android.settingslib.core.AbstractPreferenceController; 58 import com.android.settingslib.core.lifecycle.Lifecycle; 59 60 import java.util.ArrayList; 61 import java.util.Arrays; 62 import java.util.List; 63 64 /** 65 * Dashboard fragment to display application information from Settings. This activity presents 66 * extended information associated with a package like code, data, total size, permissions 67 * used by the application and also the set of default launchable activities. 68 * For system applications, an option to clear user data is displayed only if data size is > 0. 69 * System applications that do not want clear user data do not have this option. 70 * For non-system applications, there is no option to clear data. Instead there is an option to 71 * uninstall the application. 72 */ 73 public class AppInfoDashboardFragment extends DashboardFragment 74 implements ApplicationsState.Callbacks, 75 ButtonActionDialogFragment.AppButtonsDialogListener { 76 77 private static final String TAG = "AppInfoDashboard"; 78 79 // Menu identifiers 80 @VisibleForTesting 81 static final int UNINSTALL_ALL_USERS_MENU = 1; 82 @VisibleForTesting 83 static final int UNINSTALL_UPDATES = 2; 84 static final int INSTALL_INSTANT_APP_MENU = 3; 85 86 // Result code identifiers 87 @VisibleForTesting 88 static final int REQUEST_UNINSTALL = 0; 89 private static final int REQUEST_REMOVE_DEVICE_ADMIN = 5; 90 91 static final int SUB_INFO_FRAGMENT = 1; 92 93 static final int LOADER_CHART_DATA = 2; 94 static final int LOADER_STORAGE = 3; 95 static final int LOADER_BATTERY = 4; 96 static final int LOADER_BATTERY_USAGE_STATS = 5; 97 98 public static final String ARG_PACKAGE_NAME = "package"; 99 public static final String ARG_PACKAGE_UID = "uid"; 100 101 private static final boolean localLOGV = false; 102 103 private EnforcedAdmin mAppsControlDisallowedAdmin; 104 private boolean mAppsControlDisallowedBySystem; 105 106 private ApplicationsState mState; 107 private ApplicationsState.Session mSession; 108 private ApplicationsState.AppEntry mAppEntry; 109 private PackageInfo mPackageInfo; 110 private int mUserId; 111 private String mPackageName; 112 private int mUid; 113 114 private DevicePolicyManager mDpm; 115 private UserManager mUserManager; 116 private PackageManager mPm; 117 118 @VisibleForTesting 119 boolean mFinishing; 120 private boolean mListeningToPackageRemove; 121 122 123 private boolean mInitialized; 124 private boolean mShowUninstalled; 125 private boolean mUpdatedSysApp = false; 126 127 private List<Callback> mCallbacks = new ArrayList<>(); 128 129 private InstantAppButtonsPreferenceController mInstantAppButtonPreferenceController; 130 private AppButtonsPreferenceController mAppButtonsPreferenceController; 131 132 /** 133 * Callback to invoke when app info has been changed. 134 */ 135 public interface Callback { refreshUi()136 void refreshUi(); 137 } 138 139 @Override onAttach(Context context)140 public void onAttach(Context context) { 141 super.onAttach(context); 142 final String packageName = getPackageName(); 143 final TimeSpentInAppPreferenceController timeSpentInAppPreferenceController = use( 144 TimeSpentInAppPreferenceController.class); 145 timeSpentInAppPreferenceController.setPackageName(packageName); 146 timeSpentInAppPreferenceController.initLifeCycleOwner(this); 147 148 use(AppDataUsagePreferenceController.class).setParentFragment(this); 149 final AppInstallerInfoPreferenceController installer = 150 use(AppInstallerInfoPreferenceController.class); 151 installer.setPackageName(packageName); 152 installer.setParentFragment(this); 153 use(AppInstallerPreferenceCategoryController.class).setChildren(Arrays.asList(installer)); 154 use(AppNotificationPreferenceController.class).setParentFragment(this); 155 156 use(AppOpenByDefaultPreferenceController.class) 157 .setPackageName(packageName) 158 .setParentFragment(this); 159 160 use(AppPermissionPreferenceController.class).setParentFragment(this); 161 use(AppPermissionPreferenceController.class).setPackageName(packageName); 162 use(AppSettingPreferenceController.class) 163 .setPackageName(packageName) 164 .setParentFragment(this); 165 use(AppStoragePreferenceController.class).setParentFragment(this); 166 use(AppVersionPreferenceController.class).setParentFragment(this); 167 use(InstantAppDomainsPreferenceController.class).setParentFragment(this); 168 use(ExtraAppInfoPreferenceController.class).setPackageName(packageName); 169 170 final HibernationSwitchPreferenceController appHibernationSettings = 171 use(HibernationSwitchPreferenceController.class); 172 appHibernationSettings.setParentFragment(this); 173 appHibernationSettings.setPackage(packageName); 174 use(AppHibernationPreferenceCategoryController.class).setChildren( 175 Arrays.asList(appHibernationSettings)); 176 177 final WriteSystemSettingsPreferenceController writeSystemSettings = 178 use(WriteSystemSettingsPreferenceController.class); 179 writeSystemSettings.setParentFragment(this); 180 181 final DrawOverlayDetailPreferenceController drawOverlay = 182 use(DrawOverlayDetailPreferenceController.class); 183 drawOverlay.setParentFragment(this); 184 185 final PictureInPictureDetailPreferenceController pip = 186 use(PictureInPictureDetailPreferenceController.class); 187 pip.setPackageName(packageName); 188 pip.setParentFragment(this); 189 190 final ExternalSourceDetailPreferenceController externalSource = 191 use(ExternalSourceDetailPreferenceController.class); 192 externalSource.setPackageName(packageName); 193 externalSource.setParentFragment(this); 194 195 final InteractAcrossProfilesDetailsPreferenceController acrossProfiles = 196 use(InteractAcrossProfilesDetailsPreferenceController.class); 197 acrossProfiles.setPackageName(packageName); 198 acrossProfiles.setParentFragment(this); 199 200 final AlarmsAndRemindersDetailPreferenceController alarmsAndReminders = 201 use(AlarmsAndRemindersDetailPreferenceController.class); 202 alarmsAndReminders.setPackageName(packageName); 203 alarmsAndReminders.setParentFragment(this); 204 205 use(AdvancedAppInfoPreferenceCategoryController.class).setChildren(Arrays.asList( 206 writeSystemSettings, drawOverlay, pip, externalSource, acrossProfiles, 207 alarmsAndReminders)); 208 } 209 210 @Override onCreate(Bundle icicle)211 public void onCreate(Bundle icicle) { 212 super.onCreate(icicle); 213 mFinishing = false; 214 final Activity activity = getActivity(); 215 mDpm = (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE); 216 mUserManager = (UserManager) activity.getSystemService(Context.USER_SERVICE); 217 mPm = activity.getPackageManager(); 218 if (!ensurePackageInfoAvailable(activity)) { 219 return; 220 } 221 if (!ensureDisplayableModule(activity)) { 222 return; 223 } 224 startListeningToPackageRemove(); 225 226 setHasOptionsMenu(true); 227 } 228 229 @Override onCreatePreferences(Bundle savedInstanceState, String rootKey)230 public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { 231 if (!ensurePackageInfoAvailable(getActivity())) { 232 return; 233 } 234 super.onCreatePreferences(savedInstanceState, rootKey); 235 } 236 237 @Override onDestroy()238 public void onDestroy() { 239 stopListeningToPackageRemove(); 240 super.onDestroy(); 241 } 242 243 @Override getMetricsCategory()244 public int getMetricsCategory() { 245 return SettingsEnums.APPLICATIONS_INSTALLED_APP_DETAILS; 246 } 247 248 @Override onResume()249 public void onResume() { 250 super.onResume(); 251 final Activity activity = getActivity(); 252 mAppsControlDisallowedAdmin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced( 253 activity, UserManager.DISALLOW_APPS_CONTROL, mUserId); 254 mAppsControlDisallowedBySystem = RestrictedLockUtilsInternal.hasBaseUserRestriction( 255 activity, UserManager.DISALLOW_APPS_CONTROL, mUserId); 256 257 if (!refreshUi()) { 258 setIntentAndFinish(true, true); 259 } 260 } 261 262 @Override getPreferenceScreenResId()263 protected int getPreferenceScreenResId() { 264 return R.xml.app_info_settings; 265 } 266 267 @Override getLogTag()268 protected String getLogTag() { 269 return TAG; 270 } 271 272 @Override createPreferenceControllers(Context context)273 protected List<AbstractPreferenceController> createPreferenceControllers(Context context) { 274 retrieveAppEntry(); 275 if (mPackageInfo == null) { 276 return null; 277 } 278 final String packageName = getPackageName(); 279 final List<AbstractPreferenceController> controllers = new ArrayList<>(); 280 final Lifecycle lifecycle = getSettingsLifecycle(); 281 282 // The following are controllers for preferences that needs to refresh the preference state 283 // when app state changes. 284 controllers.add( 285 new AppHeaderViewPreferenceController(context, this, packageName, lifecycle)); 286 287 for (AbstractPreferenceController controller : controllers) { 288 mCallbacks.add((Callback) controller); 289 } 290 291 // The following are controllers for preferences that don't need to refresh the preference 292 // state when app state changes. 293 mInstantAppButtonPreferenceController = 294 new InstantAppButtonsPreferenceController(context, this, packageName, lifecycle); 295 controllers.add(mInstantAppButtonPreferenceController); 296 mAppButtonsPreferenceController = new AppButtonsPreferenceController( 297 (SettingsActivity) getActivity(), this, lifecycle, packageName, mState, 298 REQUEST_UNINSTALL, REQUEST_REMOVE_DEVICE_ADMIN); 299 controllers.add(mAppButtonsPreferenceController); 300 controllers.add(new AppBatteryPreferenceController( 301 context, this, packageName, getUid(), lifecycle)); 302 controllers.add(new AppMemoryPreferenceController(context, this, lifecycle)); 303 controllers.add(new DefaultHomeShortcutPreferenceController(context, packageName)); 304 controllers.add(new DefaultBrowserShortcutPreferenceController(context, packageName)); 305 controllers.add(new DefaultPhoneShortcutPreferenceController(context, packageName)); 306 controllers.add(new DefaultEmergencyShortcutPreferenceController(context, packageName)); 307 controllers.add(new DefaultSmsShortcutPreferenceController(context, packageName)); 308 309 return controllers; 310 } 311 addToCallbackList(Callback callback)312 void addToCallbackList(Callback callback) { 313 if (callback != null) { 314 mCallbacks.add(callback); 315 } 316 } 317 getAppEntry()318 ApplicationsState.AppEntry getAppEntry() { 319 return mAppEntry; 320 } 321 setAppEntry(ApplicationsState.AppEntry appEntry)322 void setAppEntry(ApplicationsState.AppEntry appEntry) { 323 mAppEntry = appEntry; 324 } 325 getPackageInfo()326 public PackageInfo getPackageInfo() { 327 return mPackageInfo; 328 } 329 330 @Override onPackageSizeChanged(String packageName)331 public void onPackageSizeChanged(String packageName) { 332 if (!TextUtils.equals(packageName, mPackageName)) { 333 Log.d(TAG, "Package change irrelevant, skipping"); 334 return; 335 } 336 refreshUi(); 337 } 338 339 /** 340 * Ensures the {@link PackageInfo} is available to proceed. If it's not available, the fragment 341 * will finish. 342 * 343 * @return true if packageInfo is available. 344 */ 345 @VisibleForTesting ensurePackageInfoAvailable(Activity activity)346 boolean ensurePackageInfoAvailable(Activity activity) { 347 if (mPackageInfo == null) { 348 mFinishing = true; 349 Log.w(TAG, "Package info not available. Is this package already uninstalled?"); 350 activity.finishAndRemoveTask(); 351 return false; 352 } 353 return true; 354 } 355 356 /** 357 * Ensures the package is displayable as directed by {@link AppUtils#isHiddenSystemModule}. 358 * If it's not, the fragment will finish. 359 * 360 * @return true if package is displayable. 361 */ 362 @VisibleForTesting ensureDisplayableModule(Activity activity)363 boolean ensureDisplayableModule(Activity activity) { 364 if (AppUtils.isHiddenSystemModule(activity.getApplicationContext(), mPackageName)) { 365 mFinishing = true; 366 Log.w(TAG, "Package is hidden module, exiting: " + mPackageName); 367 activity.finishAndRemoveTask(); 368 return false; 369 } 370 return true; 371 } 372 373 @Override onCreateOptionsMenu(Menu menu, MenuInflater inflater)374 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 375 super.onCreateOptionsMenu(menu, inflater); 376 menu.add(0, UNINSTALL_UPDATES, 0, R.string.app_factory_reset) 377 .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); 378 menu.add(0, UNINSTALL_ALL_USERS_MENU, 1, R.string.uninstall_all_users_text) 379 .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); 380 } 381 382 @Override onPrepareOptionsMenu(Menu menu)383 public void onPrepareOptionsMenu(Menu menu) { 384 if (mFinishing) { 385 return; 386 } 387 super.onPrepareOptionsMenu(menu); 388 menu.findItem(UNINSTALL_ALL_USERS_MENU).setVisible(shouldShowUninstallForAll(mAppEntry)); 389 mUpdatedSysApp = (mAppEntry.info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; 390 final MenuItem uninstallUpdatesItem = menu.findItem(UNINSTALL_UPDATES); 391 final boolean uninstallUpdateDisabled = getContext().getResources().getBoolean( 392 R.bool.config_disable_uninstall_update); 393 uninstallUpdatesItem.setVisible(mUserManager.isAdminUser() 394 && mUpdatedSysApp 395 && !mAppsControlDisallowedBySystem 396 && !uninstallUpdateDisabled); 397 if (uninstallUpdatesItem.isVisible()) { 398 RestrictedLockUtilsInternal.setMenuItemAsDisabledByAdmin(getActivity(), 399 uninstallUpdatesItem, mAppsControlDisallowedAdmin); 400 } 401 } 402 403 @Override onOptionsItemSelected(MenuItem item)404 public boolean onOptionsItemSelected(MenuItem item) { 405 switch (item.getItemId()) { 406 case UNINSTALL_ALL_USERS_MENU: 407 uninstallPkg(mAppEntry.info.packageName, true, false); 408 return true; 409 case UNINSTALL_UPDATES: 410 uninstallPkg(mAppEntry.info.packageName, false, false); 411 return true; 412 } 413 return super.onOptionsItemSelected(item); 414 } 415 416 @Override onActivityResult(int requestCode, int resultCode, Intent data)417 public void onActivityResult(int requestCode, int resultCode, Intent data) { 418 super.onActivityResult(requestCode, resultCode, data); 419 if (requestCode == REQUEST_UNINSTALL) { 420 // Refresh option menu 421 getActivity().invalidateOptionsMenu(); 422 } 423 if (mAppButtonsPreferenceController != null) { 424 mAppButtonsPreferenceController.handleActivityResult(requestCode, resultCode, data); 425 } 426 } 427 428 @Override handleDialogClick(int id)429 public void handleDialogClick(int id) { 430 if (mAppButtonsPreferenceController != null) { 431 mAppButtonsPreferenceController.handleDialogClick(id); 432 } 433 } 434 435 @VisibleForTesting shouldShowUninstallForAll(AppEntry appEntry)436 boolean shouldShowUninstallForAll(AppEntry appEntry) { 437 boolean showIt = true; 438 if (mUpdatedSysApp) { 439 showIt = false; 440 } else if (appEntry == null) { 441 showIt = false; 442 } else if ((appEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 443 showIt = false; 444 } else if (mPackageInfo == null || mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) { 445 showIt = false; 446 } else if (UserHandle.myUserId() != 0) { 447 showIt = false; 448 } else if (mUserManager.getUsers().size() < 2) { 449 showIt = false; 450 } else if (getNumberOfUserWithPackageInstalled(mPackageName) < 2 451 && (appEntry.info.flags & ApplicationInfo.FLAG_INSTALLED) != 0) { 452 showIt = false; 453 } else if (AppUtils.isInstant(appEntry.info)) { 454 showIt = false; 455 } 456 return showIt; 457 } 458 459 @VisibleForTesting refreshUi()460 boolean refreshUi() { 461 retrieveAppEntry(); 462 if (mAppEntry == null) { 463 return false; // onCreate must have failed, make sure to exit 464 } 465 466 if (mPackageInfo == null) { 467 return false; // onCreate must have failed, make sure to exit 468 } 469 470 mState.ensureIcon(mAppEntry); 471 472 // Update the preference summaries. 473 for (Callback callback : mCallbacks) { 474 callback.refreshUi(); 475 } 476 if (mAppButtonsPreferenceController.isAvailable()) { 477 mAppButtonsPreferenceController.refreshUi(); 478 } 479 480 if (!mInitialized) { 481 // First time init: are we displaying an uninstalled app? 482 mInitialized = true; 483 mShowUninstalled = (mAppEntry.info.flags & ApplicationInfo.FLAG_INSTALLED) == 0; 484 } else { 485 // All other times: if the app no longer exists then we want 486 // to go away. 487 try { 488 final ApplicationInfo ainfo = getActivity().getPackageManager().getApplicationInfo( 489 mAppEntry.info.packageName, 490 PackageManager.MATCH_DISABLED_COMPONENTS 491 | PackageManager.MATCH_ANY_USER); 492 if (!mShowUninstalled) { 493 // If we did not start out with the app uninstalled, then 494 // it transitioning to the uninstalled state for the current 495 // user means we should go away as well. 496 return (ainfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0; 497 } 498 } catch (NameNotFoundException e) { 499 return false; 500 } 501 } 502 503 return true; 504 } 505 uninstallPkg(String packageName, boolean allUsers, boolean andDisable)506 private void uninstallPkg(String packageName, boolean allUsers, boolean andDisable) { 507 stopListeningToPackageRemove(); 508 // Create new intent to launch Uninstaller activity 509 final Uri packageURI = Uri.parse("package:" + packageName); 510 final Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageURI); 511 uninstallIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, allUsers); 512 mMetricsFeatureProvider.action( 513 getContext(), SettingsEnums.ACTION_SETTINGS_UNINSTALL_APP); 514 startActivityForResult(uninstallIntent, REQUEST_UNINSTALL); 515 } 516 startAppInfoFragment(Class<?> fragment, int title, Bundle args, SettingsPreferenceFragment caller, AppEntry appEntry)517 public static void startAppInfoFragment(Class<?> fragment, int title, Bundle args, 518 SettingsPreferenceFragment caller, AppEntry appEntry) { 519 // start new fragment to display extended information 520 if (args == null) { 521 args = new Bundle(); 522 } 523 args.putString(ARG_PACKAGE_NAME, appEntry.info.packageName); 524 args.putInt(ARG_PACKAGE_UID, appEntry.info.uid); 525 new SubSettingLauncher(caller.getContext()) 526 .setDestination(fragment.getName()) 527 .setArguments(args) 528 .setTitleRes(title) 529 .setResultListener(caller, SUB_INFO_FRAGMENT) 530 .setSourceMetricsCategory(caller.getMetricsCategory()) 531 .launch(); 532 } 533 onPackageRemoved()534 private void onPackageRemoved() { 535 getActivity().finishActivity(SUB_INFO_FRAGMENT); 536 getActivity().finishAndRemoveTask(); 537 } 538 539 @VisibleForTesting getNumberOfUserWithPackageInstalled(String packageName)540 int getNumberOfUserWithPackageInstalled(String packageName) { 541 final List<UserInfo> userInfos = mUserManager.getAliveUsers(); 542 int count = 0; 543 544 for (final UserInfo userInfo : userInfos) { 545 try { 546 // Use this API to check whether user has this package 547 final ApplicationInfo info = mPm.getApplicationInfoAsUser( 548 packageName, PackageManager.GET_META_DATA, userInfo.id); 549 if ((info.flags & ApplicationInfo.FLAG_INSTALLED) != 0) { 550 count++; 551 } 552 } catch (NameNotFoundException e) { 553 Log.e(TAG, "Package: " + packageName + " not found for user: " + userInfo.id); 554 } 555 } 556 557 return count; 558 } 559 getPackageName()560 private String getPackageName() { 561 if (mPackageName != null) { 562 return mPackageName; 563 } 564 final Bundle args = getArguments(); 565 mPackageName = (args != null) ? args.getString(ARG_PACKAGE_NAME) : null; 566 if (mPackageName == null) { 567 final Intent intent = args == null ? 568 getActivity().getIntent() : (Intent) args.getParcelable("intent"); 569 if (intent != null) { 570 mPackageName = intent.getData().getSchemeSpecificPart(); 571 } 572 } 573 return mPackageName; 574 } 575 getUid()576 private int getUid() { 577 if (mUid > 0) { 578 return mUid; 579 } 580 final Bundle args = getArguments(); 581 mUid = (args != null) ? args.getInt(ARG_PACKAGE_UID) : -1; 582 if (mUid <= 0) { 583 final Intent intent = args == null 584 ? getActivity().getIntent() : (Intent) args.getParcelable("intent"); 585 mUid = intent != null && intent.getExtras() != null 586 ? mUid = intent.getIntExtra("uId", -1) : -1; 587 } 588 return mUid; 589 } 590 591 @VisibleForTesting retrieveAppEntry()592 void retrieveAppEntry() { 593 final Activity activity = getActivity(); 594 if (activity == null || mFinishing) { 595 return; 596 } 597 if (mState == null) { 598 mState = ApplicationsState.getInstance(activity.getApplication()); 599 mSession = mState.newSession(this, getSettingsLifecycle()); 600 } 601 mUserId = UserHandle.myUserId(); 602 mAppEntry = mState.getEntry(getPackageName(), UserHandle.myUserId()); 603 if (mAppEntry != null) { 604 // Get application info again to refresh changed properties of application 605 try { 606 mPackageInfo = activity.getPackageManager().getPackageInfo( 607 mAppEntry.info.packageName, 608 PackageManager.MATCH_DISABLED_COMPONENTS | 609 PackageManager.MATCH_ANY_USER | 610 PackageManager.GET_SIGNATURES | 611 PackageManager.GET_PERMISSIONS); 612 } catch (NameNotFoundException e) { 613 Log.e(TAG, "Exception when retrieving package:" + mAppEntry.info.packageName, e); 614 } 615 } else { 616 Log.w(TAG, "Missing AppEntry; maybe reinstalling?"); 617 mPackageInfo = null; 618 } 619 } 620 setIntentAndFinish(boolean finish, boolean appChanged)621 private void setIntentAndFinish(boolean finish, boolean appChanged) { 622 if (localLOGV) Log.i(TAG, "appChanged=" + appChanged); 623 final Intent intent = new Intent(); 624 intent.putExtra(ManageApplications.APP_CHG, appChanged); 625 final SettingsActivity sa = (SettingsActivity) getActivity(); 626 sa.finishPreferencePanel(Activity.RESULT_OK, intent); 627 mFinishing = true; 628 } 629 630 @Override onRunningStateChanged(boolean running)631 public void onRunningStateChanged(boolean running) { 632 // No op. 633 } 634 635 @Override onRebuildComplete(ArrayList<AppEntry> apps)636 public void onRebuildComplete(ArrayList<AppEntry> apps) { 637 // No op. 638 } 639 640 @Override onPackageIconChanged()641 public void onPackageIconChanged() { 642 // No op. 643 } 644 645 @Override onAllSizesComputed()646 public void onAllSizesComputed() { 647 // No op. 648 } 649 650 @Override onLauncherInfoChanged()651 public void onLauncherInfoChanged() { 652 // No op. 653 } 654 655 @Override onLoadEntriesCompleted()656 public void onLoadEntriesCompleted() { 657 // No op. 658 } 659 660 @Override onPackageListChanged()661 public void onPackageListChanged() { 662 if (!refreshUi()) { 663 setIntentAndFinish(true, true); 664 } 665 } 666 667 @VisibleForTesting startListeningToPackageRemove()668 void startListeningToPackageRemove() { 669 if (mListeningToPackageRemove) { 670 return; 671 } 672 mListeningToPackageRemove = true; 673 final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED); 674 filter.addDataScheme("package"); 675 getContext().registerReceiver(mPackageRemovedReceiver, filter); 676 } 677 stopListeningToPackageRemove()678 private void stopListeningToPackageRemove() { 679 if (!mListeningToPackageRemove) { 680 return; 681 } 682 mListeningToPackageRemove = false; 683 getContext().unregisterReceiver(mPackageRemovedReceiver); 684 } 685 686 @VisibleForTesting 687 final BroadcastReceiver mPackageRemovedReceiver = new BroadcastReceiver() { 688 @Override 689 public void onReceive(Context context, Intent intent) { 690 if (mFinishing) { 691 return; 692 } 693 694 final String packageName = intent.getData().getSchemeSpecificPart(); 695 if (mAppEntry == null 696 || mAppEntry.info == null 697 || TextUtils.equals(mAppEntry.info.packageName, packageName)) { 698 onPackageRemoved(); 699 } else if (mAppEntry.info.isResourceOverlay() 700 && TextUtils.equals(mPackageInfo.overlayTarget, packageName)) { 701 refreshUi(); 702 } 703 } 704 }; 705 706 } 707