Loading packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java +99 −2 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.settingslib.drawer; import android.app.ActivityManager; import android.content.Context; import android.content.IContentProvider; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; Loading @@ -24,11 +25,14 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.graphics.drawable.Icon; import android.net.Uri; import android.os.Bundle; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings.Global; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; import android.util.Pair; Loading Loading @@ -112,6 +116,15 @@ public class TileUtils { */ public static final String META_DATA_PREFERENCE_ICON = "com.android.settings.icon"; /** * Name of the meta-data item that should be set in the AndroidManifest.xml * to specify the content provider providing the icon that should be displayed for * the preference. * * Icon provided by the content provider overrides any static icon. */ public static final String META_DATA_PREFERENCE_ICON_URI = "com.android.settings.icon_uri"; /** * Name of the meta-data item that should be set in the AndroidManifest.xml * to specify the title that should be displayed for the preference. Loading @@ -124,6 +137,16 @@ public class TileUtils { */ public static final String META_DATA_PREFERENCE_SUMMARY = "com.android.settings.summary"; /** * Name of the meta-data item that should be set in the AndroidManifest.xml * to specify the content provider providing the summary text that should be displayed for the * preference. * * Summary provided by the content provider overrides any static summary. */ public static final String META_DATA_PREFERENCE_SUMMARY_URI = "com.android.settings.summary_uri"; private static final String SETTING_PKG = "com.android.settings"; /** Loading Loading @@ -315,6 +338,10 @@ public class TileUtils { CharSequence title = null; String summary = null; String keyHint = null; String uriString = null; Uri uri = null; // Several resources can be using the same provider. Only acquire a single provider. Map<String, IContentProvider> providerMap = new ArrayMap<>(); // Get the activity's meta-data try { Loading @@ -323,7 +350,11 @@ public class TileUtils { Bundle metaData = activityInfo.metaData; if (res != null && metaData != null) { if (metaData.containsKey(META_DATA_PREFERENCE_ICON)) { if (metaData.containsKey(META_DATA_PREFERENCE_ICON_URI)) { icon = getIconFromUri(context, metaData.getString(META_DATA_PREFERENCE_ICON_URI), providerMap); } if ((icon == 0) && metaData.containsKey(META_DATA_PREFERENCE_ICON)) { icon = metaData.getInt(META_DATA_PREFERENCE_ICON); } if (metaData.containsKey(META_DATA_PREFERENCE_TITLE)) { Loading @@ -333,7 +364,13 @@ public class TileUtils { title = metaData.getString(META_DATA_PREFERENCE_TITLE); } } if (metaData.containsKey(META_DATA_PREFERENCE_SUMMARY)) { if (metaData.containsKey(META_DATA_PREFERENCE_SUMMARY_URI)) { summary = getTextFromUri(context, metaData.getString(META_DATA_PREFERENCE_SUMMARY_URI), providerMap, META_DATA_PREFERENCE_SUMMARY); } if (TextUtils.isEmpty(summary) && metaData.containsKey(META_DATA_PREFERENCE_SUMMARY)) { if (metaData.get(META_DATA_PREFERENCE_SUMMARY) instanceof Integer) { summary = res.getString(metaData.getInt(META_DATA_PREFERENCE_SUMMARY)); } else { Loading Loading @@ -377,6 +414,66 @@ public class TileUtils { return false; } private static int getIconFromUri(Context context, String uriString, Map<String, IContentProvider> providerMap) { Bundle bundle = getBundleFromUri(context, uriString, providerMap); return (bundle != null) ? bundle.getInt(META_DATA_PREFERENCE_ICON, 0) : 0; } private static String getTextFromUri(Context context, String uriString, Map<String, IContentProvider> providerMap, String key) { Bundle bundle = getBundleFromUri(context, uriString, providerMap); return (bundle != null) ? bundle.getString(key) : null; } private static Bundle getBundleFromUri(Context context, String uriString, Map<String, IContentProvider> providerMap) { if (TextUtils.isEmpty(uriString)) { return null; } Uri uri = Uri.parse(uriString); String method = getMethodFromUri(uri); if (TextUtils.isEmpty(method)) { return null; } IContentProvider provider = getProviderFromUri(context, uri, providerMap); if (provider == null) { return null; } try { return provider.call(context.getPackageName(), method, uriString, null); } catch (RemoteException e) { return null; } } private static IContentProvider getProviderFromUri(Context context, Uri uri, Map<String, IContentProvider> providerMap) { if (uri == null) { return null; } String authority = uri.getAuthority(); if (TextUtils.isEmpty(authority)) { return null; } if (!providerMap.containsKey(authority)) { providerMap.put(authority, context.getContentResolver().acquireProvider(uri)); } return providerMap.get(authority); } /** Returns the first path segment of the uri if it exists as the method, otherwise null. */ static String getMethodFromUri(Uri uri) { if (uri == null) { return null; } List<String> pathSegments = uri.getPathSegments(); if ((pathSegments == null) || pathSegments.isEmpty()) { return null; } return pathSegments.get(0); } public static final Comparator<Tile> TILE_COMPARATOR = new Comparator<Tile>() { @Override Loading packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java +102 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.settingslib.drawer; import android.content.IContentProvider; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; Loading @@ -24,7 +26,9 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.net.Uri; import android.os.Bundle; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings.Global; Loading @@ -40,6 +44,7 @@ import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import java.util.ArrayList; Loading @@ -47,10 +52,12 @@ import java.util.List; import java.util.Map; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.argThat; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; @RunWith(RobolectricTestRunner.class) Loading @@ -65,12 +72,21 @@ public class TileUtilsTest { private Resources mResources; @Mock private UserManager mUserManager; @Mock private IContentProvider mIContentProvider; @Mock private ContentResolver mContentResolver; private static final String URI_GET_SUMMARY = "content://authority/text/summary"; private static final String URI_GET_ICON = "content://authority/icon/my_icon"; @Before public void setUp() throws NameNotFoundException { MockitoAnnotations.initMocks(this); when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mPackageManager.getResourcesForApplication(anyString())).thenReturn(mResources); mContentResolver = spy(RuntimeEnvironment.application.getContentResolver()); when(mContext.getContentResolver()).thenReturn(mContentResolver); } @Test Loading Loading @@ -158,11 +174,89 @@ public class TileUtilsTest { assertThat(categoryList.get(0).tiles.get(0).category).isEqualTo(testCategory); } @Test public void getTilesForIntent_shouldNotProcessInvalidUriContentSystemApp() 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); info.add(resolveInfo); when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt())) .thenReturn(info); // Case 1: No provider associated with the uri specified. TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */, false /* checkCategory */); assertThat(outTiles.size()).isEqualTo(1); assertThat(outTiles.get(0).icon.getResId()).isEqualTo(314159); assertThat(outTiles.get(0).summary).isEqualTo("static-summary"); // Case 2: Empty bundle. Bundle bundle = new Bundle(); when(mIContentProvider.call(anyString(), eq(TileUtils.getMethodFromUri(Uri.parse(URI_GET_SUMMARY))), eq(URI_GET_SUMMARY), any())).thenReturn(bundle); when(mContentResolver.acquireProvider(anyString())).thenReturn(mIContentProvider); when(mContentResolver.acquireProvider(any(Uri.class))).thenReturn(mIContentProvider); TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */, false /* checkCategory */); assertThat(outTiles.size()).isEqualTo(1); assertThat(outTiles.get(0).icon.getResId()).isEqualTo(314159); assertThat(outTiles.get(0).summary).isEqualTo("static-summary"); } @Test public void getTilesForIntent_shouldProcessUriContentForSystemApp() 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, URI_GET_ICON, URI_GET_SUMMARY); info.add(resolveInfo); when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt())) .thenReturn(info); Bundle bundle = new Bundle(); bundle.putInt("com.android.settings.icon", 161803); bundle.putString("com.android.settings.summary", "dynamic-summary"); when(mIContentProvider.call(anyString(), eq(TileUtils.getMethodFromUri(Uri.parse(URI_GET_ICON))), eq(URI_GET_ICON), any())) .thenReturn(bundle); when(mIContentProvider.call(anyString(), eq(TileUtils.getMethodFromUri(Uri.parse(URI_GET_SUMMARY))), eq(URI_GET_SUMMARY), any())).thenReturn(bundle); when(mContentResolver.acquireProvider(anyString())).thenReturn(mIContentProvider); when(mContentResolver.acquireProvider(any(Uri.class))).thenReturn(mIContentProvider); TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */, false /* checkCategory */); assertThat(outTiles.size()).isEqualTo(1); assertThat(outTiles.get(0).icon.getResId()).isEqualTo(161803); assertThat(outTiles.get(0).summary).isEqualTo("dynamic-summary"); } private ResolveInfo newInfo(boolean systemApp, String category) { return newInfo(systemApp, category, null); } private ResolveInfo newInfo(boolean systemApp, String category, String keyHint) { return newInfo(systemApp, category, keyHint, null, null); } private ResolveInfo newInfo(boolean systemApp, String category, String keyHint, String iconUri, String summaryUri) { ResolveInfo info = new ResolveInfo(); info.system = systemApp; info.activityInfo = new ActivityInfo(); Loading @@ -170,9 +264,17 @@ public class TileUtilsTest { info.activityInfo.name = "123"; info.activityInfo.metaData = new Bundle(); info.activityInfo.metaData.putString("com.android.settings.category", category); info.activityInfo.metaData.putInt("com.android.settings.icon", 314159); info.activityInfo.metaData.putString("com.android.settings.summary", "static-summary"); if (keyHint != null) { info.activityInfo.metaData.putString("com.android.settings.keyhint", keyHint); } if (iconUri != null) { info.activityInfo.metaData.putString("com.android.settings.icon_uri", iconUri); } if (summaryUri != null) { info.activityInfo.metaData.putString("com.android.settings.summary_uri", summaryUri); } info.activityInfo.applicationInfo = new ApplicationInfo(); if (systemApp) { info.activityInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; Loading Loading
packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java +99 −2 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.settingslib.drawer; import android.app.ActivityManager; import android.content.Context; import android.content.IContentProvider; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; Loading @@ -24,11 +25,14 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.graphics.drawable.Icon; import android.net.Uri; import android.os.Bundle; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings.Global; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; import android.util.Pair; Loading Loading @@ -112,6 +116,15 @@ public class TileUtils { */ public static final String META_DATA_PREFERENCE_ICON = "com.android.settings.icon"; /** * Name of the meta-data item that should be set in the AndroidManifest.xml * to specify the content provider providing the icon that should be displayed for * the preference. * * Icon provided by the content provider overrides any static icon. */ public static final String META_DATA_PREFERENCE_ICON_URI = "com.android.settings.icon_uri"; /** * Name of the meta-data item that should be set in the AndroidManifest.xml * to specify the title that should be displayed for the preference. Loading @@ -124,6 +137,16 @@ public class TileUtils { */ public static final String META_DATA_PREFERENCE_SUMMARY = "com.android.settings.summary"; /** * Name of the meta-data item that should be set in the AndroidManifest.xml * to specify the content provider providing the summary text that should be displayed for the * preference. * * Summary provided by the content provider overrides any static summary. */ public static final String META_DATA_PREFERENCE_SUMMARY_URI = "com.android.settings.summary_uri"; private static final String SETTING_PKG = "com.android.settings"; /** Loading Loading @@ -315,6 +338,10 @@ public class TileUtils { CharSequence title = null; String summary = null; String keyHint = null; String uriString = null; Uri uri = null; // Several resources can be using the same provider. Only acquire a single provider. Map<String, IContentProvider> providerMap = new ArrayMap<>(); // Get the activity's meta-data try { Loading @@ -323,7 +350,11 @@ public class TileUtils { Bundle metaData = activityInfo.metaData; if (res != null && metaData != null) { if (metaData.containsKey(META_DATA_PREFERENCE_ICON)) { if (metaData.containsKey(META_DATA_PREFERENCE_ICON_URI)) { icon = getIconFromUri(context, metaData.getString(META_DATA_PREFERENCE_ICON_URI), providerMap); } if ((icon == 0) && metaData.containsKey(META_DATA_PREFERENCE_ICON)) { icon = metaData.getInt(META_DATA_PREFERENCE_ICON); } if (metaData.containsKey(META_DATA_PREFERENCE_TITLE)) { Loading @@ -333,7 +364,13 @@ public class TileUtils { title = metaData.getString(META_DATA_PREFERENCE_TITLE); } } if (metaData.containsKey(META_DATA_PREFERENCE_SUMMARY)) { if (metaData.containsKey(META_DATA_PREFERENCE_SUMMARY_URI)) { summary = getTextFromUri(context, metaData.getString(META_DATA_PREFERENCE_SUMMARY_URI), providerMap, META_DATA_PREFERENCE_SUMMARY); } if (TextUtils.isEmpty(summary) && metaData.containsKey(META_DATA_PREFERENCE_SUMMARY)) { if (metaData.get(META_DATA_PREFERENCE_SUMMARY) instanceof Integer) { summary = res.getString(metaData.getInt(META_DATA_PREFERENCE_SUMMARY)); } else { Loading Loading @@ -377,6 +414,66 @@ public class TileUtils { return false; } private static int getIconFromUri(Context context, String uriString, Map<String, IContentProvider> providerMap) { Bundle bundle = getBundleFromUri(context, uriString, providerMap); return (bundle != null) ? bundle.getInt(META_DATA_PREFERENCE_ICON, 0) : 0; } private static String getTextFromUri(Context context, String uriString, Map<String, IContentProvider> providerMap, String key) { Bundle bundle = getBundleFromUri(context, uriString, providerMap); return (bundle != null) ? bundle.getString(key) : null; } private static Bundle getBundleFromUri(Context context, String uriString, Map<String, IContentProvider> providerMap) { if (TextUtils.isEmpty(uriString)) { return null; } Uri uri = Uri.parse(uriString); String method = getMethodFromUri(uri); if (TextUtils.isEmpty(method)) { return null; } IContentProvider provider = getProviderFromUri(context, uri, providerMap); if (provider == null) { return null; } try { return provider.call(context.getPackageName(), method, uriString, null); } catch (RemoteException e) { return null; } } private static IContentProvider getProviderFromUri(Context context, Uri uri, Map<String, IContentProvider> providerMap) { if (uri == null) { return null; } String authority = uri.getAuthority(); if (TextUtils.isEmpty(authority)) { return null; } if (!providerMap.containsKey(authority)) { providerMap.put(authority, context.getContentResolver().acquireProvider(uri)); } return providerMap.get(authority); } /** Returns the first path segment of the uri if it exists as the method, otherwise null. */ static String getMethodFromUri(Uri uri) { if (uri == null) { return null; } List<String> pathSegments = uri.getPathSegments(); if ((pathSegments == null) || pathSegments.isEmpty()) { return null; } return pathSegments.get(0); } public static final Comparator<Tile> TILE_COMPARATOR = new Comparator<Tile>() { @Override Loading
packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java +102 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.settingslib.drawer; import android.content.IContentProvider; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; Loading @@ -24,7 +26,9 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.net.Uri; import android.os.Bundle; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings.Global; Loading @@ -40,6 +44,7 @@ import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import java.util.ArrayList; Loading @@ -47,10 +52,12 @@ import java.util.List; import java.util.Map; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.argThat; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; @RunWith(RobolectricTestRunner.class) Loading @@ -65,12 +72,21 @@ public class TileUtilsTest { private Resources mResources; @Mock private UserManager mUserManager; @Mock private IContentProvider mIContentProvider; @Mock private ContentResolver mContentResolver; private static final String URI_GET_SUMMARY = "content://authority/text/summary"; private static final String URI_GET_ICON = "content://authority/icon/my_icon"; @Before public void setUp() throws NameNotFoundException { MockitoAnnotations.initMocks(this); when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mPackageManager.getResourcesForApplication(anyString())).thenReturn(mResources); mContentResolver = spy(RuntimeEnvironment.application.getContentResolver()); when(mContext.getContentResolver()).thenReturn(mContentResolver); } @Test Loading Loading @@ -158,11 +174,89 @@ public class TileUtilsTest { assertThat(categoryList.get(0).tiles.get(0).category).isEqualTo(testCategory); } @Test public void getTilesForIntent_shouldNotProcessInvalidUriContentSystemApp() 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); info.add(resolveInfo); when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt())) .thenReturn(info); // Case 1: No provider associated with the uri specified. TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */, false /* checkCategory */); assertThat(outTiles.size()).isEqualTo(1); assertThat(outTiles.get(0).icon.getResId()).isEqualTo(314159); assertThat(outTiles.get(0).summary).isEqualTo("static-summary"); // Case 2: Empty bundle. Bundle bundle = new Bundle(); when(mIContentProvider.call(anyString(), eq(TileUtils.getMethodFromUri(Uri.parse(URI_GET_SUMMARY))), eq(URI_GET_SUMMARY), any())).thenReturn(bundle); when(mContentResolver.acquireProvider(anyString())).thenReturn(mIContentProvider); when(mContentResolver.acquireProvider(any(Uri.class))).thenReturn(mIContentProvider); TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */, false /* checkCategory */); assertThat(outTiles.size()).isEqualTo(1); assertThat(outTiles.get(0).icon.getResId()).isEqualTo(314159); assertThat(outTiles.get(0).summary).isEqualTo("static-summary"); } @Test public void getTilesForIntent_shouldProcessUriContentForSystemApp() 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, URI_GET_ICON, URI_GET_SUMMARY); info.add(resolveInfo); when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt())) .thenReturn(info); Bundle bundle = new Bundle(); bundle.putInt("com.android.settings.icon", 161803); bundle.putString("com.android.settings.summary", "dynamic-summary"); when(mIContentProvider.call(anyString(), eq(TileUtils.getMethodFromUri(Uri.parse(URI_GET_ICON))), eq(URI_GET_ICON), any())) .thenReturn(bundle); when(mIContentProvider.call(anyString(), eq(TileUtils.getMethodFromUri(Uri.parse(URI_GET_SUMMARY))), eq(URI_GET_SUMMARY), any())).thenReturn(bundle); when(mContentResolver.acquireProvider(anyString())).thenReturn(mIContentProvider); when(mContentResolver.acquireProvider(any(Uri.class))).thenReturn(mIContentProvider); TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */, false /* checkCategory */); assertThat(outTiles.size()).isEqualTo(1); assertThat(outTiles.get(0).icon.getResId()).isEqualTo(161803); assertThat(outTiles.get(0).summary).isEqualTo("dynamic-summary"); } private ResolveInfo newInfo(boolean systemApp, String category) { return newInfo(systemApp, category, null); } private ResolveInfo newInfo(boolean systemApp, String category, String keyHint) { return newInfo(systemApp, category, keyHint, null, null); } private ResolveInfo newInfo(boolean systemApp, String category, String keyHint, String iconUri, String summaryUri) { ResolveInfo info = new ResolveInfo(); info.system = systemApp; info.activityInfo = new ActivityInfo(); Loading @@ -170,9 +264,17 @@ public class TileUtilsTest { info.activityInfo.name = "123"; info.activityInfo.metaData = new Bundle(); info.activityInfo.metaData.putString("com.android.settings.category", category); info.activityInfo.metaData.putInt("com.android.settings.icon", 314159); info.activityInfo.metaData.putString("com.android.settings.summary", "static-summary"); if (keyHint != null) { info.activityInfo.metaData.putString("com.android.settings.keyhint", keyHint); } if (iconUri != null) { info.activityInfo.metaData.putString("com.android.settings.icon_uri", iconUri); } if (summaryUri != null) { info.activityInfo.metaData.putString("com.android.settings.summary_uri", summaryUri); } info.activityInfo.applicationInfo = new ApplicationInfo(); if (systemApp) { info.activityInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; Loading