ManageApplications.java revision 4a01283309f737395a01f0fae68a369dc537a8da
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy 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, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.settings.applications.manageapplications; 18 19import static com.android.settings.applications.manageapplications.AppFilterRegistry 20 .FILTER_APPS_BLOCKED; 21import static com.android.settings.applications.manageapplications.AppFilterRegistry 22 .FILTER_APPS_DISABLED; 23import static com.android.settings.applications.manageapplications.AppFilterRegistry 24 .FILTER_APPS_ENABLED; 25import static com.android.settings.applications.manageapplications.AppFilterRegistry 26 .FILTER_APPS_INSTANT; 27import static com.android.settings.applications.manageapplications.AppFilterRegistry 28 .FILTER_APPS_PERSONAL; 29import static com.android.settings.applications.manageapplications.AppFilterRegistry 30 .FILTER_APPS_POWER_WHITELIST; 31import static com.android.settings.applications.manageapplications.AppFilterRegistry 32 .FILTER_APPS_POWER_WHITELIST_ALL; 33import static com.android.settings.applications.manageapplications.AppFilterRegistry 34 .FILTER_APPS_WORK; 35 36import android.annotation.Nullable; 37import android.annotation.StringRes; 38import android.app.Activity; 39import android.content.Context; 40import android.content.Intent; 41import android.content.pm.ApplicationInfo; 42import android.content.pm.PackageItemInfo; 43import android.os.Bundle; 44import android.os.Environment; 45import android.os.UserHandle; 46import android.os.UserManager; 47import android.preference.PreferenceFrameLayout; 48import android.support.annotation.VisibleForTesting; 49import android.support.v7.widget.LinearLayoutManager; 50import android.support.v7.widget.RecyclerView; 51import android.text.TextUtils; 52import android.util.ArraySet; 53import android.util.Log; 54import android.view.LayoutInflater; 55import android.view.Menu; 56import android.view.MenuInflater; 57import android.view.MenuItem; 58import android.view.View; 59import android.view.ViewGroup; 60import android.widget.AdapterView; 61import android.widget.AdapterView.OnItemSelectedListener; 62import android.widget.ArrayAdapter; 63import android.widget.FrameLayout; 64import android.widget.Spinner; 65 66import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 67import com.android.settings.R; 68import com.android.settings.Settings; 69import com.android.settings.Settings.GamesStorageActivity; 70import com.android.settings.Settings.HighPowerApplicationsActivity; 71import com.android.settings.Settings.ManageExternalSourcesActivity; 72import com.android.settings.Settings.MoviesStorageActivity; 73import com.android.settings.Settings.NotificationAppListActivity; 74import com.android.settings.Settings.OverlaySettingsActivity; 75import com.android.settings.Settings.StorageUseActivity; 76import com.android.settings.Settings.UsageAccessSettingsActivity; 77import com.android.settings.Settings.WriteSettingsActivity; 78import com.android.settings.SettingsActivity; 79import com.android.settings.applications.AppInfoBase; 80import com.android.settings.applications.AppStateAppOpsBridge.PermissionState; 81import com.android.settings.applications.AppStateBaseBridge; 82import com.android.settings.applications.AppStateInstallAppsBridge; 83import com.android.settings.applications.AppStateNotificationBridge; 84import com.android.settings.applications.AppStateOverlayBridge; 85import com.android.settings.applications.AppStatePowerBridge; 86import com.android.settings.applications.AppStateUsageBridge; 87import com.android.settings.applications.AppStateUsageBridge.UsageState; 88import com.android.settings.applications.AppStateWriteSettingsBridge; 89import com.android.settings.applications.AppStorageSettings; 90import com.android.settings.applications.DefaultAppSettings; 91import com.android.settings.applications.DrawOverlayDetails; 92import com.android.settings.applications.ExternalSourcesDetails; 93import com.android.settings.applications.InstalledAppCounter; 94import com.android.settings.applications.InstalledAppDetails; 95import com.android.settings.applications.NotificationApps; 96import com.android.settings.applications.UsageAccessDetails; 97import com.android.settings.applications.WriteSettingsDetails; 98import com.android.settings.core.InstrumentedPreferenceFragment; 99import com.android.settings.dashboard.SummaryLoader; 100import com.android.settings.fuelgauge.HighPowerDetail; 101import com.android.settings.fuelgauge.PowerWhitelistBackend; 102import com.android.settings.notification.AppNotificationSettings; 103import com.android.settings.notification.ConfigureNotificationSettings; 104import com.android.settings.notification.NotificationBackend; 105import com.android.settings.notification.NotificationBackend.AppRow; 106import com.android.settings.widget.LoadingViewController; 107import com.android.settingslib.HelpUtils; 108import com.android.settingslib.applications.ApplicationsState; 109import com.android.settingslib.applications.ApplicationsState.AppEntry; 110import com.android.settingslib.applications.ApplicationsState.AppFilter; 111import com.android.settingslib.applications.ApplicationsState.CompoundFilter; 112import com.android.settingslib.applications.ApplicationsState.VolumeFilter; 113import com.android.settingslib.applications.StorageStatsSource; 114import com.android.settingslib.utils.ThreadUtils; 115import com.android.settingslib.wrapper.PackageManagerWrapper; 116 117import java.util.ArrayList; 118import java.util.Arrays; 119import java.util.Collections; 120import java.util.Comparator; 121import java.util.Set; 122 123/** 124 * Activity to pick an application that will be used to display installation information and 125 * options to uninstall/delete user data for system applications. This activity 126 * can be launched through Settings or via the ACTION_MANAGE_PACKAGE_STORAGE 127 * intent. 128 */ 129public class ManageApplications extends InstrumentedPreferenceFragment 130 implements View.OnClickListener, OnItemSelectedListener { 131 132 static final String TAG = "ManageApplications"; 133 static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 134 135 // Intent extras. 136 public static final String EXTRA_CLASSNAME = "classname"; 137 // Used for storage only. 138 public static final String EXTRA_VOLUME_UUID = "volumeUuid"; 139 public static final String EXTRA_VOLUME_NAME = "volumeName"; 140 public static final String EXTRA_STORAGE_TYPE = "storageType"; 141 public static final String EXTRA_WORK_ONLY = "workProfileOnly"; 142 public static final String EXTRA_WORK_ID = "workId"; 143 144 private static final String EXTRA_SORT_ORDER = "sortOrder"; 145 private static final String EXTRA_SHOW_SYSTEM = "showSystem"; 146 private static final String EXTRA_HAS_ENTRIES = "hasEntries"; 147 private static final String EXTRA_HAS_BRIDGE = "hasBridge"; 148 149 // attributes used as keys when passing values to InstalledAppDetails activity 150 public static final String APP_CHG = "chg"; 151 152 // constant value that can be used to check return code from sub activity. 153 private static final int INSTALLED_APP_DETAILS = 1; 154 private static final int ADVANCED_SETTINGS = 2; 155 156 public static final int SIZE_TOTAL = 0; 157 public static final int SIZE_INTERNAL = 1; 158 public static final int SIZE_EXTERNAL = 2; 159 160 // Storage types. Used to determine what the extra item in the list of preferences is. 161 public static final int STORAGE_TYPE_DEFAULT = 0; // Show all apps that are not categorized. 162 public static final int STORAGE_TYPE_MUSIC = 1; 163 public static final int STORAGE_TYPE_LEGACY = 2; // Show apps even if they can be categorized. 164 public static final int STORAGE_TYPE_PHOTOS_VIDEOS = 3; 165 166 private static final int NO_USER_SPECIFIED = -1; 167 168 // sort order 169 private int mSortOrder = R.id.sort_order_alpha; 170 171 // whether showing system apps. 172 private boolean mShowSystem; 173 174 private ApplicationsState mApplicationsState; 175 176 public int mListType; 177 private AppFilterItem mFilter; 178 private ApplicationsAdapter mApplications; 179 180 private View mLoadingContainer; 181 182 private View mListContainer; 183 private RecyclerView mRecyclerView; 184 185 // Size resource used for packages whose size computation failed for some reason 186 CharSequence mInvalidSizeStr; 187 188 private String mCurrentPkgName; 189 private int mCurrentUid; 190 191 private Menu mOptionsMenu; 192 193 public static final int LIST_TYPE_MAIN = 0; 194 public static final int LIST_TYPE_NOTIFICATION = 1; 195 public static final int LIST_TYPE_STORAGE = 3; 196 public static final int LIST_TYPE_USAGE_ACCESS = 4; 197 public static final int LIST_TYPE_HIGH_POWER = 5; 198 public static final int LIST_TYPE_OVERLAY = 6; 199 public static final int LIST_TYPE_WRITE_SETTINGS = 7; 200 public static final int LIST_TYPE_MANAGE_SOURCES = 8; 201 public static final int LIST_TYPE_GAMES = 9; 202 public static final int LIST_TYPE_MOVIES = 10; 203 public static final int LIST_TYPE_PHOTOGRAPHY = 11; 204 205 // List types that should show instant apps. 206 public static final Set<Integer> LIST_TYPES_WITH_INSTANT = new ArraySet<>(Arrays.asList( 207 LIST_TYPE_MAIN, 208 LIST_TYPE_STORAGE)); 209 210 private View mRootView; 211 private View mSpinnerHeader; 212 private Spinner mFilterSpinner; 213 private FilterSpinnerAdapter mFilterAdapter; 214 private NotificationBackend mNotifBackend; 215 private ResetAppsHelper mResetAppsHelper; 216 private String mVolumeUuid; 217 private int mStorageType; 218 private boolean mIsWorkOnly; 219 private int mWorkUserId; 220 private View mEmptyView; 221 222 @Override 223 public void onCreate(Bundle savedInstanceState) { 224 super.onCreate(savedInstanceState); 225 setHasOptionsMenu(true); 226 final Activity activity = getActivity(); 227 mApplicationsState = ApplicationsState.getInstance(activity.getApplication()); 228 229 Intent intent = activity.getIntent(); 230 Bundle args = getArguments(); 231 int screenTitle = intent.getIntExtra( 232 SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RESID, R.string.notifications_label); 233 String className = args != null ? args.getString(EXTRA_CLASSNAME) : null; 234 if (className == null) { 235 className = intent.getComponent().getClassName(); 236 } 237 if (className.equals(NotificationAppListActivity.class.getName()) 238 || this instanceof NotificationApps) { 239 mListType = LIST_TYPE_NOTIFICATION; 240 mNotifBackend = new NotificationBackend(); 241 screenTitle = R.string.app_notifications_title; 242 } else if (className.equals(StorageUseActivity.class.getName())) { 243 if (args != null && args.containsKey(EXTRA_VOLUME_UUID)) { 244 mVolumeUuid = args.getString(EXTRA_VOLUME_UUID); 245 mStorageType = args.getInt(EXTRA_STORAGE_TYPE, STORAGE_TYPE_DEFAULT); 246 mListType = LIST_TYPE_STORAGE; 247 } else { 248 // No volume selected, display a normal list, sorted by size. 249 mListType = LIST_TYPE_MAIN; 250 } 251 mSortOrder = R.id.sort_order_size; 252 } else if (className.equals(UsageAccessSettingsActivity.class.getName())) { 253 mListType = LIST_TYPE_USAGE_ACCESS; 254 screenTitle = R.string.usage_access; 255 } else if (className.equals(HighPowerApplicationsActivity.class.getName())) { 256 mListType = LIST_TYPE_HIGH_POWER; 257 // Default to showing system. 258 mShowSystem = true; 259 screenTitle = R.string.high_power_apps; 260 } else if (className.equals(OverlaySettingsActivity.class.getName())) { 261 mListType = LIST_TYPE_OVERLAY; 262 screenTitle = R.string.system_alert_window_settings; 263 } else if (className.equals(WriteSettingsActivity.class.getName())) { 264 mListType = LIST_TYPE_WRITE_SETTINGS; 265 screenTitle = R.string.write_settings; 266 } else if (className.equals(ManageExternalSourcesActivity.class.getName())) { 267 mListType = LIST_TYPE_MANAGE_SOURCES; 268 screenTitle = R.string.install_other_apps; 269 } else if (className.equals(GamesStorageActivity.class.getName())) { 270 mListType = LIST_TYPE_GAMES; 271 mSortOrder = R.id.sort_order_size; 272 } else if (className.equals(MoviesStorageActivity.class.getName())) { 273 mListType = LIST_TYPE_MOVIES; 274 mSortOrder = R.id.sort_order_size; 275 } else if (className.equals(Settings.PhotosStorageActivity.class.getName())) { 276 mListType = LIST_TYPE_PHOTOGRAPHY; 277 mSortOrder = R.id.sort_order_size; 278 mStorageType = args.getInt(EXTRA_STORAGE_TYPE, STORAGE_TYPE_DEFAULT); 279 } else { 280 mListType = LIST_TYPE_MAIN; 281 } 282 final AppFilterRegistry appFilterRegistry = AppFilterRegistry.getInstance(); 283 mFilter = appFilterRegistry.get(appFilterRegistry.getDefaultFilterType(mListType)); 284 mIsWorkOnly = args != null ? args.getBoolean(EXTRA_WORK_ONLY) : false; 285 mWorkUserId = args != null ? args.getInt(EXTRA_WORK_ID) : NO_USER_SPECIFIED; 286 287 if (savedInstanceState != null) { 288 mSortOrder = savedInstanceState.getInt(EXTRA_SORT_ORDER, mSortOrder); 289 mShowSystem = savedInstanceState.getBoolean(EXTRA_SHOW_SYSTEM, mShowSystem); 290 } 291 292 mInvalidSizeStr = activity.getText(R.string.invalid_size_value); 293 294 mResetAppsHelper = new ResetAppsHelper(activity); 295 296 if (screenTitle > 0) { 297 activity.setTitle(screenTitle); 298 } 299 } 300 301 @Override 302 public View onCreateView(LayoutInflater inflater, ViewGroup container, 303 Bundle savedInstanceState) { 304 mRootView = inflater.inflate(R.layout.manage_applications_apps, null); 305 mLoadingContainer = mRootView.findViewById(R.id.loading_container); 306 mListContainer = mRootView.findViewById(R.id.list_container); 307 if (mListContainer != null) { 308 // Create adapter and list view here 309 mEmptyView = mListContainer.findViewById(android.R.id.empty); 310 mApplications = new ApplicationsAdapter(mApplicationsState, this, mFilter, 311 savedInstanceState); 312 if (savedInstanceState != null) { 313 mApplications.mHasReceivedLoadEntries = 314 savedInstanceState.getBoolean(EXTRA_HAS_ENTRIES, false); 315 mApplications.mHasReceivedBridgeCallback = 316 savedInstanceState.getBoolean(EXTRA_HAS_BRIDGE, false); 317 } 318 int userId = mIsWorkOnly ? mWorkUserId : UserHandle.getUserId(mCurrentUid); 319 if (mStorageType == STORAGE_TYPE_MUSIC) { 320 Context context = getContext(); 321 mApplications.setExtraViewController( 322 new MusicViewHolderController( 323 context, 324 new StorageStatsSource(context), 325 mVolumeUuid, 326 UserHandle.of(userId))); 327 } else if (mStorageType == STORAGE_TYPE_PHOTOS_VIDEOS) { 328 Context context = getContext(); 329 mApplications.setExtraViewController( 330 new PhotosViewHolderController( 331 context, 332 new StorageStatsSource(context), 333 mVolumeUuid, 334 UserHandle.of(userId))); 335 } 336 mRecyclerView = mListContainer.findViewById(R.id.apps_list); 337 mRecyclerView.setLayoutManager(new LinearLayoutManager( 338 getContext(), RecyclerView.VERTICAL, false /* reverseLayout */)); 339 mRecyclerView.setAdapter(mApplications); 340 } 341 342 // We have to do this now because PreferenceFrameLayout looks at it 343 // only when the view is added. 344 if (container instanceof PreferenceFrameLayout) { 345 ((PreferenceFrameLayout.LayoutParams) mRootView.getLayoutParams()).removeBorders = true; 346 } 347 348 createHeader(); 349 350 mResetAppsHelper.onRestoreInstanceState(savedInstanceState); 351 352 return mRootView; 353 } 354 355 @VisibleForTesting 356 void createHeader() { 357 final Activity activity = getActivity(); 358 final FrameLayout pinnedHeader = mRootView.findViewById(R.id.pinned_header); 359 mSpinnerHeader = activity.getLayoutInflater() 360 .inflate(R.layout.apps_filter_spinner, pinnedHeader, false); 361 mFilterSpinner = mSpinnerHeader.findViewById(R.id.filter_spinner); 362 mFilterAdapter = new FilterSpinnerAdapter(this); 363 mFilterSpinner.setAdapter(mFilterAdapter); 364 mFilterSpinner.setOnItemSelectedListener(this); 365 pinnedHeader.addView(mSpinnerHeader, 0); 366 367 final AppFilterRegistry appFilterRegistry = AppFilterRegistry.getInstance(); 368 mFilterAdapter.enableFilter(appFilterRegistry.getDefaultFilterType(mListType)); 369 if (mListType == LIST_TYPE_MAIN) { 370 if (UserManager.get(getActivity()).getUserProfiles().size() > 1) { 371 mFilterAdapter.enableFilter(FILTER_APPS_PERSONAL); 372 mFilterAdapter.enableFilter(FILTER_APPS_WORK); 373 } 374 } 375 if (mListType == LIST_TYPE_NOTIFICATION) { 376 mFilterAdapter.enableFilter(FILTER_APPS_BLOCKED); 377 } 378 if (mListType == LIST_TYPE_HIGH_POWER) { 379 mFilterAdapter.enableFilter(FILTER_APPS_POWER_WHITELIST_ALL); 380 } 381 382 AppFilter compositeFilter = getCompositeFilter(mListType, mStorageType, mVolumeUuid); 383 if (mIsWorkOnly) { 384 final AppFilter workFilter = appFilterRegistry.get(FILTER_APPS_WORK).getFilter(); 385 compositeFilter = new CompoundFilter(compositeFilter, workFilter); 386 } 387 if (compositeFilter != null) { 388 mApplications.setCompositeFilter(compositeFilter); 389 } 390 } 391 392 @VisibleForTesting 393 @Nullable 394 static AppFilter getCompositeFilter(int listType, int storageType, String volumeUuid) { 395 AppFilter filter = new VolumeFilter(volumeUuid); 396 if (listType == LIST_TYPE_STORAGE) { 397 if (storageType == STORAGE_TYPE_MUSIC) { 398 filter = new CompoundFilter(ApplicationsState.FILTER_AUDIO, filter); 399 } else if (storageType == STORAGE_TYPE_DEFAULT) { 400 filter = new CompoundFilter(ApplicationsState.FILTER_OTHER_APPS, filter); 401 } 402 return filter; 403 } 404 if (listType == LIST_TYPE_GAMES) { 405 return new CompoundFilter(ApplicationsState.FILTER_GAMES, filter); 406 } else if (listType == LIST_TYPE_MOVIES) { 407 return new CompoundFilter(ApplicationsState.FILTER_MOVIES, filter); 408 } else if (listType == LIST_TYPE_PHOTOGRAPHY) { 409 return new CompoundFilter(ApplicationsState.FILTER_PHOTOS, filter); 410 } 411 412 return null; 413 } 414 415 @Override 416 public int getMetricsCategory() { 417 switch (mListType) { 418 case LIST_TYPE_MAIN: 419 return MetricsEvent.MANAGE_APPLICATIONS; 420 case LIST_TYPE_NOTIFICATION: 421 return MetricsEvent.MANAGE_APPLICATIONS_NOTIFICATIONS; 422 case LIST_TYPE_STORAGE: 423 if (mStorageType == STORAGE_TYPE_MUSIC) { 424 return MetricsEvent.APPLICATIONS_STORAGE_MUSIC; 425 } 426 return MetricsEvent.APPLICATIONS_STORAGE_APPS; 427 case LIST_TYPE_GAMES: 428 return MetricsEvent.APPLICATIONS_STORAGE_GAMES; 429 case LIST_TYPE_MOVIES: 430 return MetricsEvent.APPLICATIONS_STORAGE_MOVIES; 431 case LIST_TYPE_PHOTOGRAPHY: 432 return MetricsEvent.APPLICATIONS_STORAGE_PHOTOS; 433 case LIST_TYPE_USAGE_ACCESS: 434 return MetricsEvent.USAGE_ACCESS; 435 case LIST_TYPE_HIGH_POWER: 436 return MetricsEvent.APPLICATIONS_HIGH_POWER_APPS; 437 case LIST_TYPE_OVERLAY: 438 return MetricsEvent.SYSTEM_ALERT_WINDOW_APPS; 439 case LIST_TYPE_WRITE_SETTINGS: 440 return MetricsEvent.SYSTEM_ALERT_WINDOW_APPS; 441 case LIST_TYPE_MANAGE_SOURCES: 442 return MetricsEvent.MANAGE_EXTERNAL_SOURCES; 443 default: 444 return MetricsEvent.VIEW_UNKNOWN; 445 } 446 } 447 448 @Override 449 public void onStart() { 450 super.onStart(); 451 updateView(); 452 if (mApplications != null) { 453 mApplications.resume(mSortOrder); 454 mApplications.updateLoading(); 455 } 456 } 457 458 @Override 459 public void onSaveInstanceState(Bundle outState) { 460 super.onSaveInstanceState(outState); 461 mResetAppsHelper.onSaveInstanceState(outState); 462 outState.putInt(EXTRA_SORT_ORDER, mSortOrder); 463 outState.putBoolean(EXTRA_SHOW_SYSTEM, mShowSystem); 464 outState.putBoolean(EXTRA_HAS_ENTRIES, mApplications.mHasReceivedLoadEntries); 465 outState.putBoolean(EXTRA_HAS_BRIDGE, mApplications.mHasReceivedBridgeCallback); 466 if (mApplications != null) { 467 mApplications.onSaveInstanceState(outState); 468 } 469 } 470 471 @Override 472 public void onStop() { 473 super.onStop(); 474 if (mApplications != null) { 475 mApplications.pause(); 476 } 477 mResetAppsHelper.stop(); 478 } 479 480 @Override 481 public void onDestroyView() { 482 super.onDestroyView(); 483 484 if (mApplications != null) { 485 mApplications.release(); 486 } 487 mRootView = null; 488 } 489 490 @Override 491 public void onActivityResult(int requestCode, int resultCode, Intent data) { 492 if (requestCode == INSTALLED_APP_DETAILS && mCurrentPkgName != null) { 493 if (mListType == LIST_TYPE_NOTIFICATION) { 494 mApplications.mExtraInfoBridge.forceUpdate(mCurrentPkgName, mCurrentUid); 495 } else if (mListType == LIST_TYPE_HIGH_POWER || mListType == LIST_TYPE_OVERLAY 496 || mListType == LIST_TYPE_WRITE_SETTINGS) { 497 mApplications.mExtraInfoBridge.forceUpdate(mCurrentPkgName, mCurrentUid); 498 } else { 499 mApplicationsState.requestSize(mCurrentPkgName, UserHandle.getUserId(mCurrentUid)); 500 } 501 } 502 } 503 504 // utility method used to start sub activity 505 private void startApplicationDetailsActivity() { 506 switch (mListType) { 507 case LIST_TYPE_NOTIFICATION: 508 startAppInfoFragment(AppNotificationSettings.class, R.string.notifications_title); 509 break; 510 case LIST_TYPE_USAGE_ACCESS: 511 startAppInfoFragment(UsageAccessDetails.class, R.string.usage_access); 512 break; 513 case LIST_TYPE_STORAGE: 514 startAppInfoFragment(AppStorageSettings.class, R.string.storage_settings); 515 break; 516 case LIST_TYPE_HIGH_POWER: 517 HighPowerDetail.show(this, mCurrentPkgName, INSTALLED_APP_DETAILS); 518 break; 519 case LIST_TYPE_OVERLAY: 520 startAppInfoFragment(DrawOverlayDetails.class, R.string.overlay_settings); 521 break; 522 case LIST_TYPE_WRITE_SETTINGS: 523 startAppInfoFragment(WriteSettingsDetails.class, R.string.write_system_settings); 524 break; 525 case LIST_TYPE_MANAGE_SOURCES: 526 startAppInfoFragment(ExternalSourcesDetails.class, R.string.install_other_apps); 527 break; 528 case LIST_TYPE_GAMES: 529 startAppInfoFragment(AppStorageSettings.class, R.string.game_storage_settings); 530 break; 531 case LIST_TYPE_MOVIES: 532 startAppInfoFragment(AppStorageSettings.class, R.string.storage_movies_tv); 533 break; 534 case LIST_TYPE_PHOTOGRAPHY: 535 startAppInfoFragment(AppStorageSettings.class, R.string.storage_photos_videos); 536 break; 537 // TODO: Figure out if there is a way where we can spin up the profile's settings 538 // process ahead of time, to avoid a long load of data when user clicks on a managed 539 // app. Maybe when they load the list of apps that contains managed profile apps. 540 default: 541 startAppInfoFragment(InstalledAppDetails.class, R.string.application_info_label); 542 break; 543 } 544 } 545 546 private void startAppInfoFragment(Class<?> fragment, int titleRes) { 547 AppInfoBase.startAppInfoFragment(fragment, titleRes, mCurrentPkgName, mCurrentUid, this, 548 INSTALLED_APP_DETAILS, getMetricsCategory()); 549 } 550 551 @Override 552 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 553 final Activity activity = getActivity(); 554 if (activity == null) { 555 return; 556 } 557 HelpUtils.prepareHelpMenuItem(activity, menu, getHelpResource(), getClass().getName()); 558 mOptionsMenu = menu; 559 inflater.inflate(R.menu.manage_apps, menu); 560 updateOptionsMenu(); 561 } 562 563 @Override 564 public void onPrepareOptionsMenu(Menu menu) { 565 updateOptionsMenu(); 566 } 567 568 @Override 569 public void onDestroyOptionsMenu() { 570 mOptionsMenu = null; 571 } 572 573 @StringRes 574 int getHelpResource() { 575 if (mListType == LIST_TYPE_MAIN) { 576 return R.string.help_uri_apps; 577 } else if (mListType == LIST_TYPE_USAGE_ACCESS) { 578 return R.string.help_url_usage_access; 579 } else { 580 return R.string.help_uri_notifications; 581 } 582 } 583 584 void updateOptionsMenu() { 585 if (mOptionsMenu == null) { 586 return; 587 } 588 mOptionsMenu.findItem(R.id.advanced).setVisible(false); 589 590 mOptionsMenu.findItem(R.id.sort_order_alpha).setVisible(mListType == LIST_TYPE_STORAGE 591 && mSortOrder != R.id.sort_order_alpha); 592 mOptionsMenu.findItem(R.id.sort_order_size).setVisible(mListType == LIST_TYPE_STORAGE 593 && mSortOrder != R.id.sort_order_size); 594 595 mOptionsMenu.findItem(R.id.show_system).setVisible(!mShowSystem 596 && mListType != LIST_TYPE_HIGH_POWER); 597 mOptionsMenu.findItem(R.id.hide_system).setVisible(mShowSystem 598 && mListType != LIST_TYPE_HIGH_POWER); 599 600 mOptionsMenu.findItem(R.id.reset_app_preferences).setVisible(mListType == LIST_TYPE_MAIN); 601 } 602 603 @Override 604 public boolean onOptionsItemSelected(MenuItem item) { 605 int menuId = item.getItemId(); 606 switch (item.getItemId()) { 607 case R.id.sort_order_alpha: 608 case R.id.sort_order_size: 609 mSortOrder = menuId; 610 if (mApplications != null) { 611 mApplications.rebuild(mSortOrder); 612 } 613 break; 614 case R.id.show_system: 615 case R.id.hide_system: 616 mShowSystem = !mShowSystem; 617 mApplications.rebuild(); 618 break; 619 case R.id.reset_app_preferences: 620 mResetAppsHelper.buildResetDialog(); 621 return true; 622 case R.id.advanced: 623 if (mListType == LIST_TYPE_NOTIFICATION) { 624 ((SettingsActivity) getActivity()).startPreferencePanel(this, 625 ConfigureNotificationSettings.class.getName(), null, 626 R.string.configure_notification_settings, null, this, 627 ADVANCED_SETTINGS); 628 } else { 629 ((SettingsActivity) getActivity()).startPreferencePanel(this, 630 DefaultAppSettings.class.getName(), null, R.string.configure_apps, 631 null, this, ADVANCED_SETTINGS); 632 } 633 return true; 634 default: 635 // Handle the home button 636 return false; 637 } 638 updateOptionsMenu(); 639 return true; 640 } 641 642 @Override 643 public void onClick(View view) { 644 if (mApplications == null) { 645 return; 646 } 647 final int position = mRecyclerView.getChildAdapterPosition(view); 648 649 if (position == RecyclerView.NO_POSITION) { 650 Log.w(TAG, "Cannot find position for child, skipping onClick handling"); 651 return; 652 } 653 if (mApplications.getApplicationCount() > position) { 654 ApplicationsState.AppEntry entry = mApplications.getAppEntry(position); 655 mCurrentPkgName = entry.info.packageName; 656 mCurrentUid = entry.info.uid; 657 startApplicationDetailsActivity(); 658 } else { 659 mApplications.mExtraViewController.onClick(this); 660 } 661 } 662 663 @Override 664 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { 665 mFilter = mFilterAdapter.getFilter(position); 666 mApplications.setFilter(mFilter); 667 if (DEBUG) Log.d(TAG, "Selecting filter " + mFilter); 668 } 669 670 @Override 671 public void onNothingSelected(AdapterView<?> parent) { 672 } 673 674 public void updateView() { 675 updateOptionsMenu(); 676 final Activity host = getActivity(); 677 if (host != null) { 678 host.invalidateOptionsMenu(); 679 } 680 } 681 682 public void setHasDisabled(boolean hasDisabledApps) { 683 if (mListType != LIST_TYPE_MAIN) { 684 return; 685 } 686 mFilterAdapter.setFilterEnabled(FILTER_APPS_ENABLED, hasDisabledApps); 687 mFilterAdapter.setFilterEnabled(FILTER_APPS_DISABLED, hasDisabledApps); 688 } 689 690 public void setHasInstant(boolean haveInstantApps) { 691 if (LIST_TYPES_WITH_INSTANT.contains(mListType)) { 692 mFilterAdapter.setFilterEnabled(FILTER_APPS_INSTANT, haveInstantApps); 693 } 694 } 695 696 static class FilterSpinnerAdapter extends ArrayAdapter<CharSequence> { 697 698 private final ManageApplications mManageApplications; 699 private final Context mContext; 700 701 // Use ArrayAdapter for view logic, but have our own list for managing 702 // the options available. 703 private final ArrayList<AppFilterItem> mFilterOptions = new ArrayList<>(); 704 705 public FilterSpinnerAdapter(ManageApplications manageApplications) { 706 super(manageApplications.getContext(), R.layout.filter_spinner_item); 707 mContext = manageApplications.getContext(); 708 mManageApplications = manageApplications; 709 setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 710 } 711 712 public AppFilterItem getFilter(int position) { 713 return mFilterOptions.get(position); 714 } 715 716 public void setFilterEnabled(@AppFilterRegistry.FilterType int filter, boolean enabled) { 717 if (enabled) { 718 enableFilter(filter); 719 } else { 720 disableFilter(filter); 721 } 722 } 723 724 public void enableFilter(@AppFilterRegistry.FilterType int filterType) { 725 final AppFilterItem filter = AppFilterRegistry.getInstance().get(filterType); 726 if (mFilterOptions.contains(filter)) { 727 return; 728 } 729 if (DEBUG) { 730 Log.d(TAG, "Enabling filter " + filter); 731 } 732 mFilterOptions.add(filter); 733 Collections.sort(mFilterOptions); 734 mManageApplications.mSpinnerHeader.setVisibility( 735 mFilterOptions.size() > 1 ? View.VISIBLE : View.GONE); 736 notifyDataSetChanged(); 737 if (mFilterOptions.size() == 1) { 738 if (DEBUG) { 739 Log.d(TAG, "Auto selecting filter " + filter); 740 } 741 mManageApplications.mFilterSpinner.setSelection(0); 742 mManageApplications.onItemSelected(null, null, 0, 0); 743 } 744 } 745 746 public void disableFilter(@AppFilterRegistry.FilterType int filterType) { 747 final AppFilterItem filter = AppFilterRegistry.getInstance().get(filterType); 748 if (!mFilterOptions.remove(filter)) { 749 return; 750 } 751 if (DEBUG) { 752 Log.d(TAG, "Disabling filter " + filter); 753 } 754 Collections.sort(mFilterOptions); 755 mManageApplications.mSpinnerHeader.setVisibility( 756 mFilterOptions.size() > 1 ? View.VISIBLE : View.GONE); 757 notifyDataSetChanged(); 758 if (mManageApplications.mFilter == filter) { 759 if (mFilterOptions.size() > 0) { 760 if (DEBUG) { 761 Log.d(TAG, "Auto selecting filter " + mFilterOptions.get(0)); 762 } 763 mManageApplications.mFilterSpinner.setSelection(0); 764 mManageApplications.onItemSelected(null, null, 0, 0); 765 } 766 } 767 } 768 769 @Override 770 public int getCount() { 771 return mFilterOptions.size(); 772 } 773 774 @Override 775 public CharSequence getItem(int position) { 776 return mContext.getText(mFilterOptions.get(position).getTitle()); 777 } 778 } 779 780 static class ApplicationsAdapter extends RecyclerView.Adapter<ApplicationViewHolder> 781 implements ApplicationsState.Callbacks, AppStateBaseBridge.Callback { 782 783 private static final String STATE_LAST_SCROLL_INDEX = "state_last_scroll_index"; 784 private static final int VIEW_TYPE_APP = 0; 785 private static final int VIEW_TYPE_EXTRA_VIEW = 1; 786 787 private final ApplicationsState mState; 788 private final ApplicationsState.Session mSession; 789 private final ManageApplications mManageApplications; 790 private final Context mContext; 791 private final AppStateBaseBridge mExtraInfoBridge; 792 private final LoadingViewController mLoadingViewController; 793 794 private AppFilterItem mAppFilter; 795 private ArrayList<ApplicationsState.AppEntry> mEntries; 796 private boolean mResumed; 797 private int mLastSortMode = -1; 798 private int mWhichSize = SIZE_TOTAL; 799 private AppFilter mCompositeFilter; 800 private boolean mHasReceivedLoadEntries; 801 private boolean mHasReceivedBridgeCallback; 802 private FileViewHolderController mExtraViewController; 803 804 // These two variables are used to remember and restore the last scroll position when this 805 // fragment is paused. We need this special handling because app entries are added gradually 806 // when we rebuild the list after the user made some changes, like uninstalling an app. 807 private int mLastIndex = -1; 808 809 public ApplicationsAdapter(ApplicationsState state, ManageApplications manageApplications, 810 AppFilterItem appFilter, Bundle savedInstanceState) { 811 setHasStableIds(true); 812 mState = state; 813 mSession = state.newSession(this); 814 mManageApplications = manageApplications; 815 mLoadingViewController = new LoadingViewController( 816 mManageApplications.mLoadingContainer, 817 mManageApplications.mListContainer 818 ); 819 mContext = manageApplications.getActivity(); 820 mAppFilter = appFilter; 821 if (mManageApplications.mListType == LIST_TYPE_NOTIFICATION) { 822 mExtraInfoBridge = new AppStateNotificationBridge(mContext, mState, this, 823 manageApplications.mNotifBackend); 824 } else if (mManageApplications.mListType == LIST_TYPE_USAGE_ACCESS) { 825 mExtraInfoBridge = new AppStateUsageBridge(mContext, mState, this); 826 } else if (mManageApplications.mListType == LIST_TYPE_HIGH_POWER) { 827 mExtraInfoBridge = new AppStatePowerBridge(mState, this); 828 } else if (mManageApplications.mListType == LIST_TYPE_OVERLAY) { 829 mExtraInfoBridge = new AppStateOverlayBridge(mContext, mState, this); 830 } else if (mManageApplications.mListType == LIST_TYPE_WRITE_SETTINGS) { 831 mExtraInfoBridge = new AppStateWriteSettingsBridge(mContext, mState, this); 832 } else if (mManageApplications.mListType == LIST_TYPE_MANAGE_SOURCES) { 833 mExtraInfoBridge = new AppStateInstallAppsBridge(mContext, mState, this); 834 } else { 835 mExtraInfoBridge = null; 836 } 837 if (savedInstanceState != null) { 838 mLastIndex = savedInstanceState.getInt(STATE_LAST_SCROLL_INDEX); 839 } 840 } 841 842 public void setCompositeFilter(AppFilter compositeFilter) { 843 mCompositeFilter = compositeFilter; 844 rebuild(); 845 } 846 847 public void setFilter(AppFilterItem appFilter) { 848 mAppFilter = appFilter; 849 rebuild(); 850 } 851 852 public void setExtraViewController(FileViewHolderController extraViewController) { 853 mExtraViewController = extraViewController; 854 // Start to query extra view's stats on background, and once done post result to main 855 // thread. 856 ThreadUtils.postOnBackgroundThread(() -> { 857 mExtraViewController.queryStats(); 858 ThreadUtils.postOnMainThread(() -> { 859 onExtraViewCompleted(); 860 }); 861 }); 862 } 863 864 public void resume(int sort) { 865 if (DEBUG) Log.i(TAG, "Resume! mResumed=" + mResumed); 866 if (!mResumed) { 867 mResumed = true; 868 mSession.onResume(); 869 mLastSortMode = sort; 870 if (mExtraInfoBridge != null) { 871 mExtraInfoBridge.resume(); 872 } 873 rebuild(); 874 } else { 875 rebuild(sort); 876 } 877 } 878 879 public void pause() { 880 if (mResumed) { 881 mResumed = false; 882 mSession.onPause(); 883 if (mExtraInfoBridge != null) { 884 mExtraInfoBridge.pause(); 885 } 886 } 887 } 888 889 public void onSaveInstanceState(Bundle outState) { 890 // Record the current scroll position before pausing. 891 final LinearLayoutManager layoutManager = 892 (LinearLayoutManager) mManageApplications.mRecyclerView.getLayoutManager(); 893 outState.putInt(STATE_LAST_SCROLL_INDEX, layoutManager.findFirstVisibleItemPosition()); 894 } 895 896 public void release() { 897 mSession.onDestroy(); 898 if (mExtraInfoBridge != null) { 899 mExtraInfoBridge.release(); 900 } 901 } 902 903 public void rebuild(int sort) { 904 if (sort == mLastSortMode) { 905 return; 906 } 907 mLastSortMode = sort; 908 rebuild(); 909 } 910 911 @Override 912 public ApplicationViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 913 final View view = ApplicationViewHolder.newView(parent); 914 return new ApplicationViewHolder(view, 915 shouldUseStableItemHeight(mManageApplications.mListType)); 916 } 917 918 @Override 919 public int getItemViewType(int position) { 920 boolean isLastItem = (getItemCount() - 1) == position; 921 return hasExtraView() && isLastItem 922 ? VIEW_TYPE_EXTRA_VIEW 923 : VIEW_TYPE_APP; 924 } 925 926 public void rebuild() { 927 if (!mHasReceivedLoadEntries 928 || (mExtraInfoBridge != null && !mHasReceivedBridgeCallback)) { 929 // Don't rebuild the list until all the app entries are loaded. 930 return; 931 } 932 ApplicationsState.AppFilter filterObj; 933 Comparator<AppEntry> comparatorObj; 934 boolean emulated = Environment.isExternalStorageEmulated(); 935 if (emulated) { 936 mWhichSize = SIZE_TOTAL; 937 } else { 938 mWhichSize = SIZE_INTERNAL; 939 } 940 filterObj = mAppFilter.getFilter(); 941 if (mCompositeFilter != null) { 942 filterObj = new CompoundFilter(filterObj, mCompositeFilter); 943 } 944 if (!mManageApplications.mShowSystem) { 945 if (LIST_TYPES_WITH_INSTANT.contains(mManageApplications.mListType)) { 946 filterObj = new CompoundFilter(filterObj, 947 ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_AND_INSTANT); 948 } else { 949 filterObj = new CompoundFilter(filterObj, 950 ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER); 951 } 952 } 953 switch (mLastSortMode) { 954 case R.id.sort_order_size: 955 switch (mWhichSize) { 956 case SIZE_INTERNAL: 957 comparatorObj = ApplicationsState.INTERNAL_SIZE_COMPARATOR; 958 break; 959 case SIZE_EXTERNAL: 960 comparatorObj = ApplicationsState.EXTERNAL_SIZE_COMPARATOR; 961 break; 962 default: 963 comparatorObj = ApplicationsState.SIZE_COMPARATOR; 964 break; 965 } 966 break; 967 default: 968 comparatorObj = ApplicationsState.ALPHA_COMPARATOR; 969 break; 970 } 971 972 filterObj = new CompoundFilter(filterObj, ApplicationsState.FILTER_NOT_HIDE); 973 AppFilter finalFilterObj = filterObj; 974 ThreadUtils.postOnBackgroundThread(() -> { 975 final ArrayList<AppEntry> entries = mSession.rebuild(finalFilterObj, 976 comparatorObj, false); 977 if (entries != null) { 978 ThreadUtils.postOnMainThread(() -> onRebuildComplete(entries)); 979 } 980 }); 981 } 982 983 @VisibleForTesting 984 static boolean shouldUseStableItemHeight(int listType) { 985 switch (listType) { 986 case LIST_TYPE_NOTIFICATION: 987 // Most entries in notification type has no summary. Don't use stable height 988 // so height is short for most entries. 989 return false; 990 default: 991 // Other types have non-empty summary, so keep the height as we expect summary 992 // to fill in. 993 return true; 994 } 995 } 996 997 private static boolean packageNameEquals(PackageItemInfo info1, PackageItemInfo info2) { 998 if (info1 == null || info2 == null) { 999 return false; 1000 } 1001 if (info1.packageName == null || info2.packageName == null) { 1002 return false; 1003 } 1004 return info1.packageName.equals(info2.packageName); 1005 } 1006 1007 private ArrayList<ApplicationsState.AppEntry> removeDuplicateIgnoringUser( 1008 ArrayList<ApplicationsState.AppEntry> entries) { 1009 int size = entries.size(); 1010 // returnList will not have more entries than entries 1011 ArrayList<ApplicationsState.AppEntry> returnEntries = new ArrayList<>(size); 1012 1013 // assume appinfo of same package but different users are grouped together 1014 PackageItemInfo lastInfo = null; 1015 for (int i = 0; i < size; i++) { 1016 AppEntry appEntry = entries.get(i); 1017 PackageItemInfo info = appEntry.info; 1018 if (!packageNameEquals(lastInfo, appEntry.info)) { 1019 returnEntries.add(appEntry); 1020 } 1021 lastInfo = info; 1022 } 1023 returnEntries.trimToSize(); 1024 return returnEntries; 1025 } 1026 1027 @Override 1028 public void onRebuildComplete(ArrayList<AppEntry> entries) { 1029 final int filterType = mAppFilter.getFilterType(); 1030 if (filterType == FILTER_APPS_POWER_WHITELIST || 1031 filterType == FILTER_APPS_POWER_WHITELIST_ALL) { 1032 entries = removeDuplicateIgnoringUser(entries); 1033 } 1034 mEntries = entries; 1035 notifyDataSetChanged(); 1036 if (getItemCount() == 0) { 1037 mManageApplications.mRecyclerView.setVisibility(View.GONE); 1038 mManageApplications.mEmptyView.setVisibility(View.VISIBLE); 1039 } else { 1040 mManageApplications.mEmptyView.setVisibility(View.GONE); 1041 mManageApplications.mRecyclerView.setVisibility(View.VISIBLE); 1042 } 1043 // Restore the last scroll position if the number of entries added so far is bigger than 1044 // it. 1045 if (mLastIndex != -1 && getItemCount() > mLastIndex) { 1046 mManageApplications.mRecyclerView.getLayoutManager().scrollToPosition(mLastIndex); 1047 mLastIndex = -1; 1048 } 1049 1050 if (mSession.getAllApps().size() != 0 1051 && mManageApplications.mListContainer.getVisibility() != View.VISIBLE) { 1052 mLoadingViewController.showContent(true /* animate */); 1053 } 1054 if (mManageApplications.mListType == LIST_TYPE_USAGE_ACCESS) { 1055 // No enabled or disabled filters for usage access. 1056 return; 1057 } 1058 1059 mManageApplications.setHasDisabled(mState.haveDisabledApps()); 1060 mManageApplications.setHasInstant(mState.haveInstantApps()); 1061 } 1062 1063 @VisibleForTesting 1064 void updateLoading() { 1065 final boolean appLoaded = mHasReceivedLoadEntries && mSession.getAllApps().size() != 0; 1066 if (appLoaded) { 1067 mLoadingViewController.showContent(false /* animate */); 1068 } else { 1069 mLoadingViewController.showLoadingViewDelayed(); 1070 } 1071 } 1072 1073 @Override 1074 public void onExtraInfoUpdated() { 1075 mHasReceivedBridgeCallback = true; 1076 rebuild(); 1077 } 1078 1079 @Override 1080 public void onRunningStateChanged(boolean running) { 1081 mManageApplications.getActivity().setProgressBarIndeterminateVisibility(running); 1082 } 1083 1084 @Override 1085 public void onPackageListChanged() { 1086 rebuild(); 1087 } 1088 1089 @Override 1090 public void onPackageIconChanged() { 1091 // We ensure icons are loaded when their item is displayed, so 1092 // don't care about icons loaded in the background. 1093 } 1094 1095 @Override 1096 public void onLoadEntriesCompleted() { 1097 mHasReceivedLoadEntries = true; 1098 // We may have been skipping rebuilds until this came in, trigger one now. 1099 rebuild(); 1100 } 1101 1102 @Override 1103 public void onPackageSizeChanged(String packageName) { 1104 if (mEntries == null) { 1105 return; 1106 } 1107 final int size = mEntries.size(); 1108 for (int i = 0; i < size; i++) { 1109 final AppEntry entry = mEntries.get(i); 1110 final ApplicationInfo info = entry.info; 1111 if (info == null && !TextUtils.equals(packageName, info.packageName)) { 1112 continue; 1113 } 1114 if (TextUtils.equals(mManageApplications.mCurrentPkgName, info.packageName)) { 1115 // We got the size information for the last app the 1116 // user viewed, and are sorting by size... they may 1117 // have cleared data, so we immediately want to resort 1118 // the list with the new size to reflect it to the user. 1119 rebuild(); 1120 return; 1121 } else { 1122 notifyItemChanged(i); 1123 } 1124 1125 } 1126 } 1127 1128 @Override 1129 public void onLauncherInfoChanged() { 1130 if (!mManageApplications.mShowSystem) { 1131 rebuild(); 1132 } 1133 } 1134 1135 @Override 1136 public void onAllSizesComputed() { 1137 if (mLastSortMode == R.id.sort_order_size) { 1138 rebuild(); 1139 } 1140 } 1141 1142 public void onExtraViewCompleted() { 1143 if (!hasExtraView()) { 1144 return; 1145 } 1146 // Update last item - this is assumed to be the extra view. 1147 notifyItemChanged(getItemCount() - 1); 1148 } 1149 1150 @Override 1151 public int getItemCount() { 1152 if (mEntries == null) { 1153 return 0; 1154 } 1155 return mEntries.size() + (hasExtraView() ? 1 : 0); 1156 } 1157 1158 public int getApplicationCount() { 1159 return mEntries != null ? mEntries.size() : 0; 1160 } 1161 1162 public AppEntry getAppEntry(int position) { 1163 return mEntries.get(position); 1164 } 1165 1166 @Override 1167 public long getItemId(int position) { 1168 if (position == mEntries.size()) { 1169 return -1; 1170 } 1171 return mEntries.get(position).id; 1172 } 1173 1174 public boolean isEnabled(int position) { 1175 if (getItemViewType(position) == VIEW_TYPE_EXTRA_VIEW 1176 || mManageApplications.mListType != LIST_TYPE_HIGH_POWER) { 1177 return true; 1178 } 1179 ApplicationsState.AppEntry entry = mEntries.get(position); 1180 return !PowerWhitelistBackend.getInstance().isSysWhitelisted(entry.info.packageName); 1181 } 1182 1183 @Override 1184 public void onBindViewHolder(ApplicationViewHolder holder, int position) { 1185 if (mEntries != null && mExtraViewController != null && position == mEntries.size()) { 1186 // set up view for extra view controller 1187 mExtraViewController.setupView(holder); 1188 } else { 1189 // Bind the data efficiently with the holder 1190 ApplicationsState.AppEntry entry = mEntries.get(position); 1191 synchronized (entry) { 1192 holder.setTitle(entry.label); 1193 mState.ensureIcon(entry); 1194 holder.setIcon(entry.icon); 1195 updateSummary(holder, entry); 1196 holder.updateDisableView(entry.info); 1197 } 1198 holder.setEnabled(isEnabled(position)); 1199 } 1200 holder.itemView.setOnClickListener(mManageApplications); 1201 } 1202 1203 private void updateSummary(ApplicationViewHolder holder, AppEntry entry) { 1204 switch (mManageApplications.mListType) { 1205 case LIST_TYPE_NOTIFICATION: 1206 if (entry.extraInfo != null) { 1207 holder.setSummary(InstalledAppDetails.getNotificationSummary( 1208 (AppRow) entry.extraInfo, mContext)); 1209 } else { 1210 holder.setSummary(null); 1211 } 1212 break; 1213 case LIST_TYPE_USAGE_ACCESS: 1214 if (entry.extraInfo != null) { 1215 holder.setSummary( 1216 (new UsageState((PermissionState) entry.extraInfo)).isPermissible() 1217 ? R.string.app_permission_summary_allowed 1218 : R.string.app_permission_summary_not_allowed); 1219 } else { 1220 holder.setSummary(null); 1221 } 1222 break; 1223 case LIST_TYPE_HIGH_POWER: 1224 holder.setSummary(HighPowerDetail.getSummary(mContext, entry)); 1225 break; 1226 case LIST_TYPE_OVERLAY: 1227 holder.setSummary(DrawOverlayDetails.getSummary(mContext, entry)); 1228 break; 1229 case LIST_TYPE_WRITE_SETTINGS: 1230 holder.setSummary(WriteSettingsDetails.getSummary(mContext, entry)); 1231 break; 1232 case LIST_TYPE_MANAGE_SOURCES: 1233 holder.setSummary(ExternalSourcesDetails.getPreferenceSummary(mContext, entry)); 1234 break; 1235 default: 1236 holder.updateSizeText(entry, mManageApplications.mInvalidSizeStr, mWhichSize); 1237 break; 1238 } 1239 } 1240 1241 private boolean hasExtraView() { 1242 return mExtraViewController != null 1243 && mExtraViewController.shouldShow(); 1244 } 1245 } 1246 1247 private static class SummaryProvider implements SummaryLoader.SummaryProvider { 1248 1249 private final Context mContext; 1250 private final SummaryLoader mLoader; 1251 private ApplicationsState.Session mSession; 1252 1253 private SummaryProvider(Context context, SummaryLoader loader) { 1254 mContext = context; 1255 mLoader = loader; 1256 } 1257 1258 @Override 1259 public void setListening(boolean listening) { 1260 if (listening) { 1261 new InstalledAppCounter(mContext, InstalledAppCounter.IGNORE_INSTALL_REASON, 1262 new PackageManagerWrapper(mContext.getPackageManager())) { 1263 @Override 1264 protected void onCountComplete(int num) { 1265 mLoader.setSummary(SummaryProvider.this, 1266 mContext.getString(R.string.apps_summary, num)); 1267 } 1268 }.execute(); 1269 } 1270 } 1271 } 1272 1273 public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY 1274 = new SummaryLoader.SummaryProviderFactory() { 1275 @Override 1276 public SummaryLoader.SummaryProvider createSummaryProvider(Activity activity, 1277 SummaryLoader summaryLoader) { 1278 return new SummaryProvider(activity, summaryLoader); 1279 } 1280 }; 1281} 1282