diff --git a/res/values/config.xml b/res/values/config.xml index 7901a4cc17e..9069340be09 100755 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -586,4 +586,8 @@ 0.5 + + 20 diff --git a/src/com/android/settings/SettingsApplication.java b/src/com/android/settings/SettingsApplication.java index 353208d6dc7..fc56e934f01 100644 --- a/src/com/android/settings/SettingsApplication.java +++ b/src/com/android/settings/SettingsApplication.java @@ -20,6 +20,7 @@ import android.app.Application; import com.android.settings.activityembedding.ActivityEmbeddingRulesController; import com.android.settings.homepage.SettingsHomepageActivity; +import com.android.settingslib.applications.AppIconCacheManager; import java.lang.ref.WeakReference; @@ -44,4 +45,10 @@ public class SettingsApplication extends Application { public SettingsHomepageActivity getHomeActivity() { return mHomeActivity.get(); } + + @Override + public void onLowMemory() { + super.onLowMemory(); + AppIconCacheManager.getInstance().release(); + } } diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java index 01bc2f19bb9..879bfde2a0e 100644 --- a/src/com/android/settings/applications/manageapplications/ManageApplications.java +++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java @@ -43,6 +43,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageItemInfo; +import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -125,6 +126,8 @@ import com.android.settings.notification.app.AppNotificationSettings; import com.android.settings.widget.LoadingViewController; import com.android.settings.wifi.AppStateChangeWifiStateBridge; import com.android.settings.wifi.ChangeWifiStateDetails; +import com.android.settingslib.applications.AppIconCacheManager; +import com.android.settingslib.applications.AppUtils; import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.applications.ApplicationsState.AppEntry; import com.android.settingslib.applications.ApplicationsState.AppFilter; @@ -556,6 +559,7 @@ public class ManageApplications extends InstrumentedFragment mApplications.release(); } mRootView = null; + AppIconCacheManager.getInstance().release(); } @Override @@ -1323,6 +1327,11 @@ public class ManageApplications extends InstrumentedFragment if (DEBUG) { Log.d(TAG, "onRebuildComplete size=" + entries.size()); } + + // Preload top visible icons of app list. + AppUtils.preloadTopIcons(mContext, entries, + mContext.getResources().getInteger(R.integer.config_num_visible_app_icons)); + final int filterType = mAppFilter.getFilterType(); if (filterType == FILTER_APPS_POWER_ALLOWLIST || filterType == FILTER_APPS_POWER_ALLOWLIST_ALL) { @@ -1480,8 +1489,7 @@ public class ManageApplications extends InstrumentedFragment synchronized (entry) { mState.ensureLabelDescription(entry); holder.setTitle(entry.label, entry.labelDescription); - mState.ensureIcon(entry); - holder.setIcon(entry.icon); + updateIcon(holder, entry); updateSummary(holder, entry); updateSwitch(holder, entry); holder.updateDisableView(entry.info); @@ -1491,6 +1499,20 @@ public class ManageApplications extends InstrumentedFragment holder.itemView.setOnClickListener(mManageApplications); } + private void updateIcon(ApplicationViewHolder holder, AppEntry entry) { + final Drawable cachedIcon = AppUtils.getIconFromCache(entry); + if (cachedIcon != null && entry.mounted) { + holder.setIcon(cachedIcon); + } else { + ThreadUtils.postOnBackgroundThread(() -> { + final Drawable icon = AppUtils.getIcon(mContext, entry); + if (icon != null) { + ThreadUtils.postOnMainThread(() -> holder.setIcon(icon)); + } + }); + } + } + private void updateSummary(ApplicationViewHolder holder, AppEntry entry) { switch (mManageApplications.mListType) { case LIST_TYPE_NOTIFICATION: diff --git a/src/com/android/settings/datausage/UnrestrictedDataAccess.java b/src/com/android/settings/datausage/UnrestrictedDataAccess.java index 6d8a4bad249..319ab6fe5a3 100644 --- a/src/com/android/settings/datausage/UnrestrictedDataAccess.java +++ b/src/com/android/settings/datausage/UnrestrictedDataAccess.java @@ -25,6 +25,7 @@ import android.view.View; import com.android.settings.R; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settingslib.applications.AppIconCacheManager; import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.applications.ApplicationsState.AppFilter; import com.android.settingslib.search.SearchIndexable; @@ -112,6 +113,12 @@ public class UnrestrictedDataAccess extends DashboardFragment { return R.xml.unrestricted_data_access_settings; } + @Override + public void onDestroyView() { + super.onDestroyView(); + AppIconCacheManager.getInstance().release(); + } + public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider(R.xml.unrestricted_data_access_settings); } diff --git a/src/com/android/settings/datausage/UnrestrictedDataAccessPreference.java b/src/com/android/settings/datausage/UnrestrictedDataAccessPreference.java index a41b5828b46..cd26ed16e8f 100644 --- a/src/com/android/settings/datausage/UnrestrictedDataAccessPreference.java +++ b/src/com/android/settings/datausage/UnrestrictedDataAccessPreference.java @@ -16,6 +16,7 @@ package com.android.settings.datausage; import static com.android.settingslib.RestrictedLockUtilsInternal.checkIfMeteredDataRestricted; import android.content.Context; +import android.graphics.drawable.Drawable; import android.os.UserHandle; import android.view.View; @@ -26,8 +27,10 @@ import com.android.settings.applications.appinfo.AppInfoDashboardFragment; import com.android.settings.dashboard.DashboardFragment; import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; import com.android.settingslib.RestrictedPreferenceHelper; +import com.android.settingslib.applications.AppUtils; import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.applications.ApplicationsState.AppEntry; +import com.android.settingslib.utils.ThreadUtils; import com.android.settingslib.widget.AppSwitchPreference; public class UnrestrictedDataAccessPreference extends AppSwitchPreference implements @@ -39,6 +42,7 @@ public class UnrestrictedDataAccessPreference extends AppSwitchPreference implem private final DataSaverBackend mDataSaverBackend; private final DashboardFragment mParentFragment; private final RestrictedPreferenceHelper mHelper; + private Drawable mCacheIcon; public UnrestrictedDataAccessPreference(final Context context, AppEntry entry, ApplicationsState applicationsState, DataSaverBackend dataSaverBackend, @@ -56,8 +60,13 @@ public class UnrestrictedDataAccessPreference extends AppSwitchPreference implem UserHandle.getUserId(entry.info.uid))); updateState(); setKey(generateKey(mEntry)); - if (mEntry.icon != null) { - setIcon(mEntry.icon); + + mCacheIcon = AppUtils.getIconFromCache(mEntry); + if (mCacheIcon != null) { + setIcon(mCacheIcon); + } else { + // Set empty icon as default. + setIcon(R.drawable.empty_icon); } } @@ -101,16 +110,13 @@ public class UnrestrictedDataAccessPreference extends AppSwitchPreference implem @Override public void onBindViewHolder(PreferenceViewHolder holder) { - if (mEntry.icon == null) { - holder.itemView.post(new Runnable() { - @Override - public void run() { - // Ensure we have an icon before binding. - mApplicationsState.ensureIcon(mEntry); - // This might trigger us to bind again, but it gives an easy way to only - // load the icon once its needed, so its probably worth it. - setIcon(mEntry.icon); - } + if (mCacheIcon == null) { + ThreadUtils.postOnBackgroundThread(() -> { + final Drawable icon = AppUtils.getIcon(getContext(), mEntry); + ThreadUtils.postOnMainThread(() -> { + setIcon(icon); + mCacheIcon = icon; + }); }); } final boolean disabledByAdmin = isDisabledByAdmin(); diff --git a/src/com/android/settings/datausage/UnrestrictedDataAccessPreferenceController.java b/src/com/android/settings/datausage/UnrestrictedDataAccessPreferenceController.java index e3c79a7e8a7..ac088c037e0 100644 --- a/src/com/android/settings/datausage/UnrestrictedDataAccessPreferenceController.java +++ b/src/com/android/settings/datausage/UnrestrictedDataAccessPreferenceController.java @@ -29,6 +29,7 @@ import com.android.settings.applications.AppStateBaseBridge; import com.android.settings.core.BasePreferenceController; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.overlay.FeatureFactory; +import com.android.settingslib.applications.AppUtils; import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.applications.ApplicationsState.AppEntry; import com.android.settingslib.applications.ApplicationsState.AppFilter; @@ -125,6 +126,10 @@ public class UnrestrictedDataAccessPreferenceController extends BasePreferenceCo return; } + // Preload top visible icons of app list. + AppUtils.preloadTopIcons(mContext, apps, + mContext.getResources().getInteger(R.integer.config_num_visible_app_icons)); + // Create apps key set for removing useless preferences final Set appsKeySet = new TreeSet<>(); // Add or update preferences