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
This commit is contained in:
@@ -19,27 +19,30 @@ package com.android.settings.applications.managedomainurls;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.verify.domain.DomainVerificationManager;
|
import android.content.pm.verify.domain.DomainVerificationManager;
|
||||||
import android.content.pm.verify.domain.DomainVerificationUserState;
|
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.R;
|
||||||
import com.android.settings.applications.intentpicker.IntentPickerUtils;
|
import com.android.settings.applications.intentpicker.IntentPickerUtils;
|
||||||
|
import com.android.settingslib.applications.AppUtils;
|
||||||
import com.android.settingslib.applications.ApplicationsState.AppEntry;
|
import com.android.settingslib.applications.ApplicationsState.AppEntry;
|
||||||
|
import com.android.settingslib.utils.ThreadUtils;
|
||||||
import com.android.settingslib.widget.AppPreference;
|
import com.android.settingslib.widget.AppPreference;
|
||||||
|
|
||||||
public class DomainAppPreference extends AppPreference {
|
public class DomainAppPreference extends AppPreference {
|
||||||
|
|
||||||
|
private Drawable mCacheIcon;
|
||||||
|
|
||||||
private final AppEntry mEntry;
|
private final AppEntry mEntry;
|
||||||
private final DomainVerificationManager mDomainVerificationManager;
|
private final DomainVerificationManager mDomainVerificationManager;
|
||||||
private final IconDrawableFactory mIconDrawableFactory;
|
|
||||||
|
|
||||||
public DomainAppPreference(final Context context, IconDrawableFactory iconFactory,
|
public DomainAppPreference(final Context context, AppEntry entry) {
|
||||||
AppEntry entry) {
|
|
||||||
super(context);
|
super(context);
|
||||||
mIconDrawableFactory = iconFactory;
|
|
||||||
mDomainVerificationManager = context.getSystemService(DomainVerificationManager.class);
|
mDomainVerificationManager = context.getSystemService(DomainVerificationManager.class);
|
||||||
mEntry = entry;
|
mEntry = entry;
|
||||||
mEntry.ensureLabel(getContext());
|
mEntry.ensureLabel(getContext());
|
||||||
|
mCacheIcon = AppUtils.getIconFromCache(mEntry);
|
||||||
setState();
|
setState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,7 +57,12 @@ public class DomainAppPreference extends AppPreference {
|
|||||||
|
|
||||||
private void setState() {
|
private void setState() {
|
||||||
setTitle(mEntry.label);
|
setTitle(mEntry.label);
|
||||||
setIcon(mIconDrawableFactory.getBadgedIcon(mEntry.info));
|
|
||||||
|
if (mCacheIcon != null) {
|
||||||
|
setIcon(mCacheIcon);
|
||||||
|
} else {
|
||||||
|
setIcon(R.drawable.empty_icon);
|
||||||
|
}
|
||||||
setSummary(getDomainsSummary(mEntry.info.packageName));
|
setSummary(getDomainsSummary(mEntry.info.packageName));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,4 +77,18 @@ public class DomainAppPreference extends AppPreference {
|
|||||||
packageName);
|
packageName);
|
||||||
return userState == null ? false : userState.isLinkHandlingAllowed();
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -20,7 +20,6 @@ import android.app.Application;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.ArrayMap;
|
import android.util.ArrayMap;
|
||||||
import android.util.IconDrawableFactory;
|
|
||||||
|
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
import androidx.preference.PreferenceGroup;
|
import androidx.preference.PreferenceGroup;
|
||||||
@@ -30,6 +29,7 @@ import com.android.settings.R;
|
|||||||
import com.android.settings.applications.AppInfoBase;
|
import com.android.settings.applications.AppInfoBase;
|
||||||
import com.android.settings.applications.intentpicker.AppLaunchSettings;
|
import com.android.settings.applications.intentpicker.AppLaunchSettings;
|
||||||
import com.android.settings.core.BasePreferenceController;
|
import com.android.settings.core.BasePreferenceController;
|
||||||
|
import com.android.settingslib.applications.AppUtils;
|
||||||
import com.android.settingslib.applications.ApplicationsState;
|
import com.android.settingslib.applications.ApplicationsState;
|
||||||
import com.android.settingslib.applications.ApplicationsState.AppEntry;
|
import com.android.settingslib.applications.ApplicationsState.AppEntry;
|
||||||
|
|
||||||
@@ -98,6 +98,10 @@ public class DomainAppPreferenceController extends BasePreferenceController impl
|
|||||||
if (mContext == null) {
|
if (mContext == null) {
|
||||||
return;
|
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);
|
rebuildAppList(mDomainAppList, apps);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,13 +161,12 @@ public class DomainAppPreferenceController extends BasePreferenceController impl
|
|||||||
cacheAllPrefs(group);
|
cacheAllPrefs(group);
|
||||||
final int size = apps.size();
|
final int size = apps.size();
|
||||||
final Context context = group.getContext();
|
final Context context = group.getContext();
|
||||||
final IconDrawableFactory iconDrawableFactory = IconDrawableFactory.newInstance(context);
|
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
final AppEntry entry = apps.get(i);
|
final AppEntry entry = apps.get(i);
|
||||||
final String key = entry.info.packageName + "|" + entry.info.uid;
|
final String key = entry.info.packageName + "|" + entry.info.uid;
|
||||||
DomainAppPreference preference = (DomainAppPreference) getCachedPreference(key);
|
DomainAppPreference preference = (DomainAppPreference) getCachedPreference(key);
|
||||||
if (preference == null) {
|
if (preference == null) {
|
||||||
preference = new DomainAppPreference(context, iconDrawableFactory, entry);
|
preference = new DomainAppPreference(context, entry);
|
||||||
preference.setKey(key);
|
preference.setKey(key);
|
||||||
group.addPreference(preference);
|
group.addPreference(preference);
|
||||||
} else {
|
} else {
|
||||||
|
@@ -24,6 +24,7 @@ import android.content.Context;
|
|||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.dashboard.DashboardFragment;
|
import com.android.settings.dashboard.DashboardFragment;
|
||||||
import com.android.settings.search.BaseSearchIndexProvider;
|
import com.android.settings.search.BaseSearchIndexProvider;
|
||||||
|
import com.android.settingslib.applications.AppIconCacheManager;
|
||||||
import com.android.settingslib.search.SearchIndexable;
|
import com.android.settingslib.search.SearchIndexable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -58,4 +59,10 @@ public class ManageDomainUrls extends DashboardFragment {
|
|||||||
|
|
||||||
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||||
new BaseSearchIndexProvider(R.xml.manage_domain_url_settings);
|
new BaseSearchIndexProvider(R.xml.manage_domain_url_settings);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroyView() {
|
||||||
|
super.onDestroyView();
|
||||||
|
AppIconCacheManager.getInstance().release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -29,7 +29,6 @@ import android.content.pm.ApplicationInfo;
|
|||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.verify.domain.DomainVerificationManager;
|
import android.content.pm.verify.domain.DomainVerificationManager;
|
||||||
import android.content.pm.verify.domain.DomainVerificationUserState;
|
import android.content.pm.verify.domain.DomainVerificationUserState;
|
||||||
import android.util.IconDrawableFactory;
|
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settingslib.applications.ApplicationsState;
|
import com.android.settingslib.applications.ApplicationsState;
|
||||||
@@ -49,18 +48,14 @@ public class DomainAppPreferenceControllerTest {
|
|||||||
|
|
||||||
private ApplicationsState.AppEntry mAppEntry;
|
private ApplicationsState.AppEntry mAppEntry;
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
private IconDrawableFactory mIconDrawableFactory;
|
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private DomainVerificationManager mDomainVerificationManager;
|
private DomainVerificationManager mDomainVerificationManager;
|
||||||
@Mock
|
|
||||||
private DomainVerificationUserState mDomainVerificationUserState;
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
mContext = spy(RuntimeEnvironment.application);
|
mContext = spy(RuntimeEnvironment.application);
|
||||||
mIconDrawableFactory = IconDrawableFactory.newInstance(mContext);
|
|
||||||
mAppEntry = new ApplicationsState.AppEntry(
|
mAppEntry = new ApplicationsState.AppEntry(
|
||||||
mContext, createApplicationInfo(mContext.getPackageName()), 0);
|
mContext, createApplicationInfo(mContext.getPackageName()), 0);
|
||||||
when(mContext.getSystemService(DomainVerificationManager.class)).thenReturn(
|
when(mContext.getSystemService(DomainVerificationManager.class)).thenReturn(
|
||||||
@@ -75,8 +70,7 @@ public class DomainAppPreferenceControllerTest {
|
|||||||
doReturn(domainVerificationUserState).when(
|
doReturn(domainVerificationUserState).when(
|
||||||
mDomainVerificationManager).getDomainVerificationUserState(anyString());
|
mDomainVerificationManager).getDomainVerificationUserState(anyString());
|
||||||
doReturn(true).when(domainVerificationUserState).isLinkHandlingAllowed();
|
doReturn(true).when(domainVerificationUserState).isLinkHandlingAllowed();
|
||||||
final DomainAppPreference pref = new DomainAppPreference(
|
final DomainAppPreference pref = new DomainAppPreference(mContext, mAppEntry);
|
||||||
mContext, mIconDrawableFactory, mAppEntry);
|
|
||||||
|
|
||||||
assertThat(pref.getLayoutResource()).isEqualTo(R.layout.preference_app);
|
assertThat(pref.getLayoutResource()).isEqualTo(R.layout.preference_app);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user