Loading packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java +16 −3 Original line number Diff line number Diff line Loading @@ -165,6 +165,9 @@ public class TileUtils { * Name of the meta-data item that should be set in the AndroidManifest.xml to specify the * custom view which should be displayed for the preference. The custom view will be inflated * as a remote view. * * This also can be used with {@link META_DATA_PREFERENCE_SUMMARY_URI} above, by setting the id * of the summary TextView to '@android:id/summary'. */ public static final String META_DATA_PREFERENCE_CUSTOM_VIEW = "com.android.settings.custom_view"; Loading Loading @@ -315,6 +318,7 @@ public class TileUtils { PackageManager pm = context.getPackageManager(); List<ResolveInfo> results = pm.queryIntentActivitiesAsUser(intent, PackageManager.GET_META_DATA, user.getIdentifier()); Map<String, IContentProvider> providerMap = new HashMap<>(); for (ResolveInfo resolved : results) { if (!resolved.system) { // Do not allow any app to add to settings, only system ones. Loading Loading @@ -346,7 +350,7 @@ public class TileUtils { tile.priority = usePriority ? resolved.priority : 0; tile.metaData = activityInfo.metaData; updateTileData(context, tile, activityInfo, activityInfo.applicationInfo, pm); pm, providerMap); if (DEBUG) Log.d(LOG_TAG, "Adding tile " + tile.title); addedCache.put(key, tile); Loading @@ -361,14 +365,14 @@ public class TileUtils { } private static boolean updateTileData(Context context, Tile tile, ActivityInfo activityInfo, ApplicationInfo applicationInfo, PackageManager pm) { ActivityInfo activityInfo, ApplicationInfo applicationInfo, PackageManager pm, Map<String, IContentProvider> providerMap) { if (applicationInfo.isSystemApp()) { int icon = 0; Pair<String, Integer> iconFromUri = null; CharSequence title = null; String summary = null; String keyHint = null; Uri uri = null; RemoteViews remoteViews = null; // Get the activity's meta-data Loading Loading @@ -414,6 +418,15 @@ public class TileUtils { if (metaData.containsKey(META_DATA_PREFERENCE_CUSTOM_VIEW)) { int layoutId = metaData.getInt(META_DATA_PREFERENCE_CUSTOM_VIEW); remoteViews = new RemoteViews(applicationInfo.packageName, layoutId); if (metaData.containsKey(META_DATA_PREFERENCE_SUMMARY_URI)) { String uriString = metaData.getString( META_DATA_PREFERENCE_SUMMARY_URI); String overrideSummary = getTextFromUri(context, uriString, providerMap, META_DATA_PREFERENCE_SUMMARY); if (overrideSummary != null) { remoteViews.setTextViewText(android.R.id.summary, overrideSummary); } } } } } catch (PackageManager.NameNotFoundException | Resources.NotFoundException e) { Loading packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java +100 −1 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import android.provider.Settings.Global; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Pair; import android.widget.RemoteViews; import com.android.settingslib.R; import com.android.settingslib.TestConfig; Loading @@ -51,6 +52,7 @@ import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.internal.ShadowExtractor; import java.util.ArrayList; import java.util.Collections; Loading @@ -68,9 +70,13 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; @RunWith(RobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION, shadows = {TileUtilsTest.TileUtilsShadowRemoteViews.class}) public class TileUtilsTest { @Mock Loading Loading @@ -364,6 +370,86 @@ public class TileUtilsTest { assertThat(tile.remoteViews.getLayoutId()).isEqualTo(R.layout.user_preference); } @Test public void getTilesForIntent_summaryUriSpecified_shouldOverrideRemoteViewSummary() throws RemoteException { Intent intent = new Intent(); Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>(); List<Tile> outTiles = new ArrayList<>(); List<ResolveInfo> info = new ArrayList<>(); ResolveInfo resolveInfo = newInfo(true, null /* category */, null, null, URI_GET_SUMMARY); resolveInfo.activityInfo.metaData.putInt("com.android.settings.custom_view", R.layout.user_preference); info.add(resolveInfo); when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt())) .thenReturn(info); // Mock the content provider interaction. Bundle bundle = new Bundle(); bundle.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY, "new summary text"); when(mIContentProvider.call(anyString(), eq(TileUtils.getMethodFromUri(Uri.parse(URI_GET_SUMMARY))), eq(URI_GET_SUMMARY), any())).thenReturn(bundle); when(mContentResolver.acquireUnstableProvider(anyString())) .thenReturn(mIContentProvider); when(mContentResolver.acquireUnstableProvider(any(Uri.class))) .thenReturn(mIContentProvider); TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */, false /* checkCategory */); assertThat(outTiles.size()).isEqualTo(1); Tile tile = outTiles.get(0); assertThat(tile.remoteViews).isNotNull(); assertThat(tile.remoteViews.getLayoutId()).isEqualTo(R.layout.user_preference); // Make sure the summary TextView got a new text string. TileUtilsShadowRemoteViews shadowRemoteViews = (TileUtilsShadowRemoteViews) ShadowExtractor.extract(tile.remoteViews); assertThat(shadowRemoteViews.overrideViewId).isEqualTo(android.R.id.summary); assertThat(shadowRemoteViews.overrideText).isEqualTo("new summary text"); } @Test public void getTilesForIntent_providerUnavailable_shouldNotOverrideRemoteViewSummary() throws RemoteException { Intent intent = new Intent(); Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>(); List<Tile> outTiles = new ArrayList<>(); List<ResolveInfo> info = new ArrayList<>(); ResolveInfo resolveInfo = newInfo(true, null /* category */, null, null, URI_GET_SUMMARY); resolveInfo.activityInfo.metaData.putInt("com.android.settings.custom_view", R.layout.user_preference); info.add(resolveInfo); when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt())) .thenReturn(info); // Mock the content provider interaction. Bundle bundle = new Bundle(); bundle.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY, "new summary text"); when(mIContentProvider.call(anyString(), eq(TileUtils.getMethodFromUri(Uri.parse(URI_GET_SUMMARY))), eq(URI_GET_SUMMARY), any())).thenReturn(bundle); TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */, false /* checkCategory */); assertThat(outTiles.size()).isEqualTo(1); Tile tile = outTiles.get(0); assertThat(tile.remoteViews).isNotNull(); assertThat(tile.remoteViews.getLayoutId()).isEqualTo(R.layout.user_preference); // Make sure the summary TextView didn't get any text view updates. TileUtilsShadowRemoteViews shadowRemoteViews = (TileUtilsShadowRemoteViews) ShadowExtractor.extract(tile.remoteViews); assertThat(shadowRemoteViews.overrideViewId).isNull(); assertThat(shadowRemoteViews.overrideText).isNull(); } public static ResolveInfo newInfo(boolean systemApp, String category) { return newInfo(systemApp, category, null); } Loading Loading @@ -423,4 +509,17 @@ public class TileUtilsTest { info.activityInfo.metaData.putString(key, value); } } @Implements(RemoteViews.class) public static class TileUtilsShadowRemoteViews { private Integer overrideViewId; private CharSequence overrideText; @Implementation public void setTextViewText(int viewId, CharSequence text) { overrideViewId = viewId; overrideText = text; } } } Loading
packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java +16 −3 Original line number Diff line number Diff line Loading @@ -165,6 +165,9 @@ public class TileUtils { * Name of the meta-data item that should be set in the AndroidManifest.xml to specify the * custom view which should be displayed for the preference. The custom view will be inflated * as a remote view. * * This also can be used with {@link META_DATA_PREFERENCE_SUMMARY_URI} above, by setting the id * of the summary TextView to '@android:id/summary'. */ public static final String META_DATA_PREFERENCE_CUSTOM_VIEW = "com.android.settings.custom_view"; Loading Loading @@ -315,6 +318,7 @@ public class TileUtils { PackageManager pm = context.getPackageManager(); List<ResolveInfo> results = pm.queryIntentActivitiesAsUser(intent, PackageManager.GET_META_DATA, user.getIdentifier()); Map<String, IContentProvider> providerMap = new HashMap<>(); for (ResolveInfo resolved : results) { if (!resolved.system) { // Do not allow any app to add to settings, only system ones. Loading Loading @@ -346,7 +350,7 @@ public class TileUtils { tile.priority = usePriority ? resolved.priority : 0; tile.metaData = activityInfo.metaData; updateTileData(context, tile, activityInfo, activityInfo.applicationInfo, pm); pm, providerMap); if (DEBUG) Log.d(LOG_TAG, "Adding tile " + tile.title); addedCache.put(key, tile); Loading @@ -361,14 +365,14 @@ public class TileUtils { } private static boolean updateTileData(Context context, Tile tile, ActivityInfo activityInfo, ApplicationInfo applicationInfo, PackageManager pm) { ActivityInfo activityInfo, ApplicationInfo applicationInfo, PackageManager pm, Map<String, IContentProvider> providerMap) { if (applicationInfo.isSystemApp()) { int icon = 0; Pair<String, Integer> iconFromUri = null; CharSequence title = null; String summary = null; String keyHint = null; Uri uri = null; RemoteViews remoteViews = null; // Get the activity's meta-data Loading Loading @@ -414,6 +418,15 @@ public class TileUtils { if (metaData.containsKey(META_DATA_PREFERENCE_CUSTOM_VIEW)) { int layoutId = metaData.getInt(META_DATA_PREFERENCE_CUSTOM_VIEW); remoteViews = new RemoteViews(applicationInfo.packageName, layoutId); if (metaData.containsKey(META_DATA_PREFERENCE_SUMMARY_URI)) { String uriString = metaData.getString( META_DATA_PREFERENCE_SUMMARY_URI); String overrideSummary = getTextFromUri(context, uriString, providerMap, META_DATA_PREFERENCE_SUMMARY); if (overrideSummary != null) { remoteViews.setTextViewText(android.R.id.summary, overrideSummary); } } } } } catch (PackageManager.NameNotFoundException | Resources.NotFoundException e) { Loading
packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java +100 −1 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import android.provider.Settings.Global; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Pair; import android.widget.RemoteViews; import com.android.settingslib.R; import com.android.settingslib.TestConfig; Loading @@ -51,6 +52,7 @@ import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.internal.ShadowExtractor; import java.util.ArrayList; import java.util.Collections; Loading @@ -68,9 +70,13 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; @RunWith(RobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION, shadows = {TileUtilsTest.TileUtilsShadowRemoteViews.class}) public class TileUtilsTest { @Mock Loading Loading @@ -364,6 +370,86 @@ public class TileUtilsTest { assertThat(tile.remoteViews.getLayoutId()).isEqualTo(R.layout.user_preference); } @Test public void getTilesForIntent_summaryUriSpecified_shouldOverrideRemoteViewSummary() throws RemoteException { Intent intent = new Intent(); Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>(); List<Tile> outTiles = new ArrayList<>(); List<ResolveInfo> info = new ArrayList<>(); ResolveInfo resolveInfo = newInfo(true, null /* category */, null, null, URI_GET_SUMMARY); resolveInfo.activityInfo.metaData.putInt("com.android.settings.custom_view", R.layout.user_preference); info.add(resolveInfo); when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt())) .thenReturn(info); // Mock the content provider interaction. Bundle bundle = new Bundle(); bundle.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY, "new summary text"); when(mIContentProvider.call(anyString(), eq(TileUtils.getMethodFromUri(Uri.parse(URI_GET_SUMMARY))), eq(URI_GET_SUMMARY), any())).thenReturn(bundle); when(mContentResolver.acquireUnstableProvider(anyString())) .thenReturn(mIContentProvider); when(mContentResolver.acquireUnstableProvider(any(Uri.class))) .thenReturn(mIContentProvider); TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */, false /* checkCategory */); assertThat(outTiles.size()).isEqualTo(1); Tile tile = outTiles.get(0); assertThat(tile.remoteViews).isNotNull(); assertThat(tile.remoteViews.getLayoutId()).isEqualTo(R.layout.user_preference); // Make sure the summary TextView got a new text string. TileUtilsShadowRemoteViews shadowRemoteViews = (TileUtilsShadowRemoteViews) ShadowExtractor.extract(tile.remoteViews); assertThat(shadowRemoteViews.overrideViewId).isEqualTo(android.R.id.summary); assertThat(shadowRemoteViews.overrideText).isEqualTo("new summary text"); } @Test public void getTilesForIntent_providerUnavailable_shouldNotOverrideRemoteViewSummary() throws RemoteException { Intent intent = new Intent(); Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>(); List<Tile> outTiles = new ArrayList<>(); List<ResolveInfo> info = new ArrayList<>(); ResolveInfo resolveInfo = newInfo(true, null /* category */, null, null, URI_GET_SUMMARY); resolveInfo.activityInfo.metaData.putInt("com.android.settings.custom_view", R.layout.user_preference); info.add(resolveInfo); when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt())) .thenReturn(info); // Mock the content provider interaction. Bundle bundle = new Bundle(); bundle.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY, "new summary text"); when(mIContentProvider.call(anyString(), eq(TileUtils.getMethodFromUri(Uri.parse(URI_GET_SUMMARY))), eq(URI_GET_SUMMARY), any())).thenReturn(bundle); TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */, false /* checkCategory */); assertThat(outTiles.size()).isEqualTo(1); Tile tile = outTiles.get(0); assertThat(tile.remoteViews).isNotNull(); assertThat(tile.remoteViews.getLayoutId()).isEqualTo(R.layout.user_preference); // Make sure the summary TextView didn't get any text view updates. TileUtilsShadowRemoteViews shadowRemoteViews = (TileUtilsShadowRemoteViews) ShadowExtractor.extract(tile.remoteViews); assertThat(shadowRemoteViews.overrideViewId).isNull(); assertThat(shadowRemoteViews.overrideText).isNull(); } public static ResolveInfo newInfo(boolean systemApp, String category) { return newInfo(systemApp, category, null); } Loading Loading @@ -423,4 +509,17 @@ public class TileUtilsTest { info.activityInfo.metaData.putString(key, value); } } @Implements(RemoteViews.class) public static class TileUtilsShadowRemoteViews { private Integer overrideViewId; private CharSequence overrideText; @Implementation public void setTextViewText(int viewId, CharSequence text) { overrideViewId = viewId; overrideText = text; } } }