Cache the summary and icons for Security Settings injected tiles.
This helps the summary and icons load more smoothly when resuming
from recents.
Bug: 35994047
Test: make RunSettingsRoboTests
Change-Id: I763f7dd19f64007959e1281f0ff04ecd19bbfbfc
(cherry picked from commit 45f4e1241d7ce15d381a1ea1e671e8eef17da94a)
diff --git a/src/com/android/settings/security/SecurityFeatureProviderImpl.java b/src/com/android/settings/security/SecurityFeatureProviderImpl.java
index 7be2d66..5a2ff2e 100644
--- a/src/com/android/settings/security/SecurityFeatureProviderImpl.java
+++ b/src/com/android/settings/security/SecurityFeatureProviderImpl.java
@@ -39,6 +39,7 @@
import com.android.settingslib.drawer.TileUtils;
import java.util.concurrent.Executors;
+import java.util.TreeMap;
import java.util.Map;
/** Implementation for {@code SecurityFeatureProvider}. */
@@ -51,6 +52,12 @@
@VisibleForTesting
static final String DEFAULT_SUMMARY = " ";
+ @VisibleForTesting
+ static Map<String, Pair<String, Integer>> sIconCache = new TreeMap<>();
+
+ @VisibleForTesting
+ static Map<String, String> sSummaryCache = new TreeMap<>();
+
/** Update preferences with data from associated tiles. */
public void updatePreferences(final Context context, final PreferenceScreen preferenceScreen,
final DashboardCategory dashboardCategory) {
@@ -89,11 +96,33 @@
if (matchingPref == null) {
continue;
}
- // Remove any icons that may be loaded before we inject the final icon.
- matchingPref.setIcon(DEFAULT_ICON);
- // Reserve room for the summary. This prevents the title from having to shift when the
- // final title is injected.
- matchingPref.setSummary(DEFAULT_SUMMARY);
+ // Either remove an icon by replacing them with nothing, or use the cached one since
+ // there is a delay in fetching the injected icon, and we don't want an inappropriate
+ // icon to be displayed while waiting for the injected icon.
+ final String iconUri =
+ tile.metaData.getString(TileUtils.META_DATA_PREFERENCE_ICON_URI, null);
+ Drawable drawable = DEFAULT_ICON;
+ if ((iconUri != null) && sIconCache.containsKey(iconUri)) {
+ Pair<String, Integer> icon = sIconCache.get(iconUri);
+ try {
+ drawable = context.getPackageManager()
+ .getResourcesForApplication(icon.first /* package name */)
+ .getDrawable(icon.second /* res id */,
+ context.getTheme());
+ } catch (PackageManager.NameNotFoundException e) {
+ // Ignore and just load the default icon.
+ }
+ }
+ matchingPref.setIcon(drawable);
+ // Either reserve room for the summary or load the cached one. This prevents the title
+ // from shifting when the final summary is injected.
+ final String summaryUri =
+ tile.metaData.getString(TileUtils.META_DATA_PREFERENCE_SUMMARY_URI, null);
+ String summary = DEFAULT_SUMMARY;
+ if ((summaryUri != null) && sSummaryCache.containsKey(summaryUri)) {
+ summary = sSummaryCache.get(summaryUri);
+ }
+ matchingPref.setSummary(summary);
}
}
@@ -115,8 +144,9 @@
continue;
}
// Check if the tile has content providers for dynamically updatable content.
- String iconUri = tile.metaData.getString(TileUtils.META_DATA_PREFERENCE_ICON_URI, null);
- String summaryUri =
+ final String iconUri =
+ tile.metaData.getString(TileUtils.META_DATA_PREFERENCE_ICON_URI, null);
+ final String summaryUri =
tile.metaData.getString(TileUtils.META_DATA_PREFERENCE_SUMMARY_URI, null);
if (!TextUtils.isEmpty(iconUri)) {
String packageName = null;
@@ -131,6 +161,7 @@
Pair<String, Integer> icon =
TileUtils.getIconFromUri(context, packageName, iconUri, providerMap);
if (icon != null) {
+ sIconCache.put(iconUri, icon);
// Icon is only returned if the icon belongs to Settings or the target app.
// setIcon must be called on the UI thread.
new Handler(Looper.getMainLooper()).post(new Runnable() {
@@ -153,6 +184,7 @@
if (!TextUtils.isEmpty(summaryUri)) {
String summary = TileUtils.getTextFromUri(context, summaryUri, providerMap,
TileUtils.META_DATA_PREFERENCE_SUMMARY);
+ sSummaryCache.put(summaryUri, summary);
// setSummary must be called on UI thread.
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
diff --git a/tests/robotests/src/com/android/settings/security/SecurityFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/security/SecurityFeatureProviderImplTest.java
index 50debb4..77f5ecc 100644
--- a/tests/robotests/src/com/android/settings/security/SecurityFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/security/SecurityFeatureProviderImplTest.java
@@ -77,7 +77,7 @@
private SecurityFeatureProviderImpl mImpl;
@Implements(com.android.settingslib.drawer.TileUtils.class)
- public static class TileUtilsMock {
+ public static class ShadowTileUtils {
@Implementation
public static Pair getIconFromUri(Context context, String packageName, String uriString,
Map<String, IContentProvider> providerMap) {
@@ -131,7 +131,7 @@
@Test
@Config(shadows = {
- TileUtilsMock.class,
+ ShadowTileUtils.class,
})
public void updateTilesData_shouldUpdateMatchingPreference() {
Bundle bundle = new Bundle();
@@ -151,7 +151,7 @@
@Test
@Config(shadows = {
- TileUtilsMock.class,
+ ShadowTileUtils.class,
})
public void updateTilesData_shouldNotUpdateAlreadyUpdatedPreference() {
Bundle bundle = new Bundle();
@@ -183,6 +183,31 @@
.setSummary(SecurityFeatureProviderImpl.DEFAULT_SUMMARY);
}
+ @Test
+ @Config(shadows = {
+ ShadowTileUtils.class,
+ })
+ public void initPreferences_shouldLoadCached() {
+ Bundle bundle = new Bundle();
+ bundle.putString(TileUtils.META_DATA_PREFERENCE_ICON_URI, URI_GET_ICON);
+ bundle.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY_URI, URI_GET_SUMMARY);
+
+ PreferenceScreen screen = getPreferenceScreen();
+ DashboardCategory dashboardCategory = getDashboardCategory();
+ dashboardCategory.getTile(0).metaData = bundle;
+
+ SecurityFeatureProviderImpl.sIconCache.put(
+ URI_GET_ICON,
+ ShadowTileUtils.getIconFromUri(null, null, null, null));
+ SecurityFeatureProviderImpl.sSummaryCache.put(
+ URI_GET_SUMMARY,
+ MOCK_SUMMARY);
+
+ mImpl.initPreferences(mContext, screen, dashboardCategory);
+ verify(screen.findPreference(MOCK_KEY)).setIcon(mMockDrawable);
+ verify(screen.findPreference(MOCK_KEY)).setSummary(MOCK_SUMMARY);
+ }
+
private PreferenceScreen getPreferenceScreen() {
final PreferenceScreen screen = mock(PreferenceScreen.class);
final Preference pref = mock(Preference.class);