From 93f945d516d2320244c1492e1117dcd4850e3cc7 Mon Sep 17 00:00:00 2001 From: Yi-Ling Chuang Date: Fri, 29 Apr 2022 19:29:02 +0800 Subject: [PATCH] Fix the flashing list on Opening link page The bottom list flashes because it takes some time to create a DomainAppPreference, where each perference takes around 6ms to load an icon. When there are, that say, 30 apps installed, then it will take around 180ms to be ready, which introduces the flashing issue. In order to tackle icon loading, this CL applies the icon cache mechanism to speed up the loading time. Fixes: 222981986 Test: robotest Change-Id: Ia8f7cbf5af5ea9f694c352ea40ccca47bedb175c --- .../managedomainurls/DomainAppPreference.java | 36 +++++++++++++++---- .../DomainAppPreferenceController.java | 9 +++-- .../managedomainurls/ManageDomainUrls.java | 7 ++++ .../DomainAppPreferenceControllerTest.java | 8 +---- 4 files changed, 43 insertions(+), 17 deletions(-) diff --git a/src/com/android/settings/applications/managedomainurls/DomainAppPreference.java b/src/com/android/settings/applications/managedomainurls/DomainAppPreference.java index 559c2abf598..f80245c26b0 100644 --- a/src/com/android/settings/applications/managedomainurls/DomainAppPreference.java +++ b/src/com/android/settings/applications/managedomainurls/DomainAppPreference.java @@ -19,27 +19,30 @@ package com.android.settings.applications.managedomainurls; import android.content.Context; import android.content.pm.verify.domain.DomainVerificationManager; import android.content.pm.verify.domain.DomainVerificationUserState; -import android.util.IconDrawableFactory; +import android.graphics.drawable.Drawable; + +import androidx.preference.PreferenceViewHolder; import com.android.settings.R; import com.android.settings.applications.intentpicker.IntentPickerUtils; +import com.android.settingslib.applications.AppUtils; import com.android.settingslib.applications.ApplicationsState.AppEntry; +import com.android.settingslib.utils.ThreadUtils; import com.android.settingslib.widget.AppPreference; public class DomainAppPreference extends AppPreference { + private Drawable mCacheIcon; + private final AppEntry mEntry; private final DomainVerificationManager mDomainVerificationManager; - private final IconDrawableFactory mIconDrawableFactory; - public DomainAppPreference(final Context context, IconDrawableFactory iconFactory, - AppEntry entry) { + public DomainAppPreference(final Context context, AppEntry entry) { super(context); - mIconDrawableFactory = iconFactory; mDomainVerificationManager = context.getSystemService(DomainVerificationManager.class); mEntry = entry; mEntry.ensureLabel(getContext()); - + mCacheIcon = AppUtils.getIconFromCache(mEntry); setState(); } @@ -54,7 +57,12 @@ public class DomainAppPreference extends AppPreference { private void setState() { setTitle(mEntry.label); - setIcon(mIconDrawableFactory.getBadgedIcon(mEntry.info)); + + if (mCacheIcon != null) { + setIcon(mCacheIcon); + } else { + setIcon(R.drawable.empty_icon); + } setSummary(getDomainsSummary(mEntry.info.packageName)); } @@ -69,4 +77,18 @@ public class DomainAppPreference extends AppPreference { packageName); return userState == null ? false : userState.isLinkHandlingAllowed(); } + + @Override + public void onBindViewHolder(PreferenceViewHolder view) { + if (mCacheIcon == null) { + ThreadUtils.postOnBackgroundThread(() -> { + final Drawable icon = AppUtils.getIcon(getContext(), mEntry); + ThreadUtils.postOnMainThread(() -> { + setIcon(icon); + mCacheIcon = icon; + }); + }); + } + super.onBindViewHolder(view); + } } diff --git a/src/com/android/settings/applications/managedomainurls/DomainAppPreferenceController.java b/src/com/android/settings/applications/managedomainurls/DomainAppPreferenceController.java index eae1d06bbbc..33cc6d58cc5 100644 --- a/src/com/android/settings/applications/managedomainurls/DomainAppPreferenceController.java +++ b/src/com/android/settings/applications/managedomainurls/DomainAppPreferenceController.java @@ -20,7 +20,6 @@ import android.app.Application; import android.content.Context; import android.text.TextUtils; import android.util.ArrayMap; -import android.util.IconDrawableFactory; import androidx.preference.Preference; import androidx.preference.PreferenceGroup; @@ -30,6 +29,7 @@ import com.android.settings.R; import com.android.settings.applications.AppInfoBase; import com.android.settings.applications.intentpicker.AppLaunchSettings; import com.android.settings.core.BasePreferenceController; +import com.android.settingslib.applications.AppUtils; import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.applications.ApplicationsState.AppEntry; @@ -98,6 +98,10 @@ public class DomainAppPreferenceController extends BasePreferenceController impl if (mContext == null) { return; } + // Preload top visible icons of app list. + AppUtils.preloadTopIcons(mContext, apps, + mContext.getResources().getInteger(R.integer.config_num_visible_app_icons)); + rebuildAppList(mDomainAppList, apps); } @@ -157,13 +161,12 @@ public class DomainAppPreferenceController extends BasePreferenceController impl cacheAllPrefs(group); final int size = apps.size(); final Context context = group.getContext(); - final IconDrawableFactory iconDrawableFactory = IconDrawableFactory.newInstance(context); for (int i = 0; i < size; i++) { final AppEntry entry = apps.get(i); final String key = entry.info.packageName + "|" + entry.info.uid; DomainAppPreference preference = (DomainAppPreference) getCachedPreference(key); if (preference == null) { - preference = new DomainAppPreference(context, iconDrawableFactory, entry); + preference = new DomainAppPreference(context, entry); preference.setKey(key); group.addPreference(preference); } else { diff --git a/src/com/android/settings/applications/managedomainurls/ManageDomainUrls.java b/src/com/android/settings/applications/managedomainurls/ManageDomainUrls.java index 82ca6b321a9..bf37c7003f3 100644 --- a/src/com/android/settings/applications/managedomainurls/ManageDomainUrls.java +++ b/src/com/android/settings/applications/managedomainurls/ManageDomainUrls.java @@ -24,6 +24,7 @@ import android.content.Context; 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.search.SearchIndexable; /** @@ -58,4 +59,10 @@ public class ManageDomainUrls extends DashboardFragment { public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider(R.xml.manage_domain_url_settings); + + @Override + public void onDestroyView() { + super.onDestroyView(); + AppIconCacheManager.getInstance().release(); + } } diff --git a/tests/robotests/src/com/android/settings/applications/managedomainurls/DomainAppPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/managedomainurls/DomainAppPreferenceControllerTest.java index 9db75a2ec68..4917a85e873 100644 --- a/tests/robotests/src/com/android/settings/applications/managedomainurls/DomainAppPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/managedomainurls/DomainAppPreferenceControllerTest.java @@ -29,7 +29,6 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.verify.domain.DomainVerificationManager; import android.content.pm.verify.domain.DomainVerificationUserState; -import android.util.IconDrawableFactory; import com.android.settings.R; import com.android.settingslib.applications.ApplicationsState; @@ -49,18 +48,14 @@ public class DomainAppPreferenceControllerTest { private ApplicationsState.AppEntry mAppEntry; private Context mContext; - private IconDrawableFactory mIconDrawableFactory; @Mock private DomainVerificationManager mDomainVerificationManager; - @Mock - private DomainVerificationUserState mDomainVerificationUserState; @Before public void setUp() { MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application); - mIconDrawableFactory = IconDrawableFactory.newInstance(mContext); mAppEntry = new ApplicationsState.AppEntry( mContext, createApplicationInfo(mContext.getPackageName()), 0); when(mContext.getSystemService(DomainVerificationManager.class)).thenReturn( @@ -75,8 +70,7 @@ public class DomainAppPreferenceControllerTest { doReturn(domainVerificationUserState).when( mDomainVerificationManager).getDomainVerificationUserState(anyString()); doReturn(true).when(domainVerificationUserState).isLinkHandlingAllowed(); - final DomainAppPreference pref = new DomainAppPreference( - mContext, mIconDrawableFactory, mAppEntry); + final DomainAppPreference pref = new DomainAppPreference(mContext, mAppEntry); assertThat(pref.getLayoutResource()).isEqualTo(R.layout.preference_app); }