Loading core/java/com/android/internal/app/ChooserActivity.java +78 −32 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityManager; Loading Loading @@ -729,7 +730,13 @@ public class ChooserActivity extends ResolverActivity { /** * Returns true if app prediction service is defined and the component exists on device. */ private boolean isAppPredictionServiceAvailable() { @VisibleForTesting public boolean isAppPredictionServiceAvailable() { if (getPackageManager().getAppPredictionServicePackageName() == null) { // Default AppPredictionService is not defined. return false; } final String appPredictionServiceName = getString(R.string.config_defaultAppPredictionService); if (appPredictionServiceName == null) { Loading Loading @@ -1584,25 +1591,19 @@ public class ChooserActivity extends ResolverActivity { // ShareShortcutInfos directly. boolean resultMessageSent = false; for (int i = 0; i < driList.size(); i++) { List<ChooserTarget> chooserTargets = new ArrayList<>(); List<ShortcutManager.ShareShortcutInfo> matchingShortcuts = new ArrayList<>(); for (int j = 0; j < resultList.size(); j++) { if (driList.get(i).getResolvedComponentName().equals( resultList.get(j).getTargetComponent())) { ShortcutManager.ShareShortcutInfo shareShortcutInfo = resultList.get(j); // Incoming results are ordered but without a score. Create a score // based on the index in order to be sorted appropriately when joined // with legacy direct share api results. float score = Math.max(1.0f - (0.05f * j), 0.0f); ChooserTarget chooserTarget = convertToChooserTarget(shareShortcutInfo, score); chooserTargets.add(chooserTarget); if (mDirectShareAppTargetCache != null && appTargets != null) { mDirectShareAppTargetCache.put(chooserTarget, appTargets.get(j)); matchingShortcuts.add(resultList.get(j)); } } } if (chooserTargets.isEmpty()) { if (matchingShortcuts.isEmpty()) { continue; } List<ChooserTarget> chooserTargets = convertToChooserTarget( matchingShortcuts, resultList, appTargets, shortcutType); final Message msg = Message.obtain(); msg.what = ChooserHandler.SHORTCUT_MANAGER_SHARE_TARGET_RESULT; msg.obj = new ServiceResultInfo(driList.get(i), chooserTargets, null); Loading Loading @@ -1640,23 +1641,69 @@ public class ChooserActivity extends ResolverActivity { return false; } private ChooserTarget convertToChooserTarget(ShortcutManager.ShareShortcutInfo shareShortcut, float score) { ShortcutInfo shortcutInfo = shareShortcut.getShortcutInfo(); /** * Converts a list of ShareShortcutInfos to ChooserTargets. * @param matchingShortcuts List of shortcuts, all from the same package, that match the current * share intent filter. * @param allShortcuts List of all the shortcuts from all the packages on the device that are * returned for the current sharing action. * @param allAppTargets List of AppTargets. Null if the results are not from prediction service. * @param shortcutType One of the values TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER or * TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE * @return A list of ChooserTargets sorted by score in descending order. */ @VisibleForTesting @NonNull public List<ChooserTarget> convertToChooserTarget( @NonNull List<ShortcutManager.ShareShortcutInfo> matchingShortcuts, @NonNull List<ShortcutManager.ShareShortcutInfo> allShortcuts, @Nullable List<AppTarget> allAppTargets, @ShareTargetType int shortcutType) { // A set of distinct scores for the matched shortcuts. We use index of a rank in the sorted // list instead of the actual rank value when converting a rank to a score. List<Integer> scoreList = new ArrayList<>(); if (shortcutType == TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER) { for (int i = 0; i < matchingShortcuts.size(); i++) { int shortcutRank = matchingShortcuts.get(i).getShortcutInfo().getRank(); if (!scoreList.contains(shortcutRank)) { scoreList.add(shortcutRank); } } Collections.sort(scoreList); } List<ChooserTarget> chooserTargetList = new ArrayList<>(matchingShortcuts.size()); for (int i = 0; i < matchingShortcuts.size(); i++) { ShortcutInfo shortcutInfo = matchingShortcuts.get(i).getShortcutInfo(); int indexInAllShortcuts = allShortcuts.indexOf(matchingShortcuts.get(i)); float score; if (shortcutType == TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE) { // Incoming results are ordered. Create a score based on index in the original list. score = Math.max(1.0f - (0.01f * indexInAllShortcuts), 0.0f); } else { // Create a score based on the rank of the shortcut. int rankIndex = scoreList.indexOf(shortcutInfo.getRank()); score = Math.max(1.0f - (0.01f * rankIndex), 0.0f); } Bundle extras = new Bundle(); extras.putString(Intent.EXTRA_SHORTCUT_ID, shortcutInfo.getId()); return new ChooserTarget( // The name of this target. shortcutInfo.getShortLabel(), // Don't load the icon until it is selected to be shown null, // The ranking score for this target (0.0-1.0); the system will omit items with low // scores when there are too many Direct Share items. score, // The name of the component to be launched if this target is chosen. shareShortcut.getTargetComponent().clone(), // The extra values here will be merged into the Intent when this target is chosen. extras); ChooserTarget chooserTarget = new ChooserTarget(shortcutInfo.getShortLabel(), null, // Icon will be loaded later if this target is selected to be shown. score, matchingShortcuts.get(i).getTargetComponent().clone(), extras); chooserTargetList.add(chooserTarget); if (mDirectShareAppTargetCache != null && allAppTargets != null) { mDirectShareAppTargetCache.put(chooserTarget, allAppTargets.get(indexInAllShortcuts)); } } // Sort ChooserTargets by score in descending order Comparator<ChooserTarget> byScore = (ChooserTarget a, ChooserTarget b) -> -Float.compare(a.getScore(), b.getScore()); Collections.sort(chooserTargetList, byScore); return chooserTargetList; } private String convertServiceName(String packageName, String serviceName) { Loading Loading @@ -1748,8 +1795,7 @@ public class ChooserActivity extends ResolverActivity { if (!mIsAppPredictorComponentAvailable) { return null; } if (mAppPredictor == null && getPackageManager().getAppPredictionServicePackageName() != null) { if (mAppPredictor == null) { final IntentFilter filter = getTargetIntentFilter(); Bundle extras = new Bundle(); extras.putParcelable(APP_PREDICTION_INTENT_FILTER_KEY, filter); Loading core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java +144 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; Loading @@ -51,6 +52,8 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager.ShareShortcutInfo; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.Canvas; Loading Loading @@ -807,6 +810,108 @@ public class ChooserActivityTest { is(testBaseScore * SHORTCUT_TARGET_SCORE_BOOST)); } /** * The case when AppPrediction service is not defined in PackageManager is already covered * as a test parameter {@link ChooserActivityTest#packageManagers}. This test is checking the * case when the prediction service is defined but the component is not available on the device. */ @Test public void testIsAppPredictionServiceAvailable() { Intent sendIntent = createSendTextIntent(); List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(), Mockito.anyBoolean(), Mockito.isA(List.class))).thenReturn(resolvedComponentInfos); final ChooserWrapperActivity activity = mActivityRule .launchActivity(Intent.createChooser(sendIntent, null)); waitForIdle(); if (activity.getPackageManager().getAppPredictionServicePackageName() == null) { assertThat(activity.isAppPredictionServiceAvailable(), is(false)); } else { assertThat(activity.isAppPredictionServiceAvailable(), is(true)); sOverrides.resources = Mockito.spy(activity.getResources()); when(sOverrides.resources.getString(R.string.config_defaultAppPredictionService)) .thenReturn("ComponentNameThatDoesNotExist"); assertThat(activity.isAppPredictionServiceAvailable(), is(false)); } } @Test public void testConvertToChooserTarget_predictionService() { Intent sendIntent = createSendTextIntent(); List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(), Mockito.anyBoolean(), Mockito.isA(List.class))).thenReturn(resolvedComponentInfos); final ChooserWrapperActivity activity = mActivityRule .launchActivity(Intent.createChooser(sendIntent, null)); waitForIdle(); List<ShareShortcutInfo> shortcuts = createShortcuts(activity); int[] expectedOrderAllShortcuts = {0, 1, 2, 3}; float[] expectedScoreAllShortcuts = {1.0f, 0.99f, 0.98f, 0.97f}; List<ChooserTarget> chooserTargets = activity.convertToChooserTarget(shortcuts, shortcuts, null, TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE); assertCorrectShortcutToChooserTargetConversion(shortcuts, chooserTargets, expectedOrderAllShortcuts, expectedScoreAllShortcuts); List<ShareShortcutInfo> subset = new ArrayList<>(); subset.add(shortcuts.get(1)); subset.add(shortcuts.get(2)); subset.add(shortcuts.get(3)); int[] expectedOrderSubset = {1, 2, 3}; float[] expectedScoreSubset = {0.99f, 0.98f, 0.97f}; chooserTargets = activity.convertToChooserTarget(subset, shortcuts, null, TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE); assertCorrectShortcutToChooserTargetConversion(shortcuts, chooserTargets, expectedOrderSubset, expectedScoreSubset); } @Test public void testConvertToChooserTarget_shortcutManager() { Intent sendIntent = createSendTextIntent(); List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(), Mockito.anyBoolean(), Mockito.isA(List.class))).thenReturn(resolvedComponentInfos); final ChooserWrapperActivity activity = mActivityRule .launchActivity(Intent.createChooser(sendIntent, null)); waitForIdle(); List<ShareShortcutInfo> shortcuts = createShortcuts(activity); int[] expectedOrderAllShortcuts = {2, 0, 3, 1}; float[] expectedScoreAllShortcuts = {1.0f, 0.99f, 0.99f, 0.98f}; List<ChooserTarget> chooserTargets = activity.convertToChooserTarget(shortcuts, shortcuts, null, TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER); assertCorrectShortcutToChooserTargetConversion(shortcuts, chooserTargets, expectedOrderAllShortcuts, expectedScoreAllShortcuts); List<ShareShortcutInfo> subset = new ArrayList<>(); subset.add(shortcuts.get(1)); subset.add(shortcuts.get(2)); subset.add(shortcuts.get(3)); int[] expectedOrderSubset = {2, 3, 1}; float[] expectedScoreSubset = {1.0f, 0.99f, 0.98f}; chooserTargets = activity.convertToChooserTarget(subset, shortcuts, null, TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER); assertCorrectShortcutToChooserTargetConversion(shortcuts, chooserTargets, expectedOrderSubset, expectedScoreSubset); } // This test is too long and too slow and should not be taken as an example for future tests. @Test public void testDirectTargetSelectionLogging() throws InterruptedException { Loading Loading @@ -1103,4 +1208,43 @@ public class ChooserActivityTest { return bitmap; } private List<ShareShortcutInfo> createShortcuts(Context context) { Intent testIntent = new Intent("TestIntent"); List<ShareShortcutInfo> shortcuts = new ArrayList<>(); shortcuts.add(new ShareShortcutInfo( new ShortcutInfo.Builder(context, "shortcut1") .setIntent(testIntent).setShortLabel("label1").setRank(3).build(), // 0 2 new ComponentName("package1", "class1"))); shortcuts.add(new ShareShortcutInfo( new ShortcutInfo.Builder(context, "shortcut2") .setIntent(testIntent).setShortLabel("label2").setRank(7).build(), // 1 3 new ComponentName("package2", "class2"))); shortcuts.add(new ShareShortcutInfo( new ShortcutInfo.Builder(context, "shortcut3") .setIntent(testIntent).setShortLabel("label3").setRank(1).build(), // 2 0 new ComponentName("package3", "class3"))); shortcuts.add(new ShareShortcutInfo( new ShortcutInfo.Builder(context, "shortcut4") .setIntent(testIntent).setShortLabel("label4").setRank(3).build(), // 3 2 new ComponentName("package4", "class4"))); return shortcuts; } private void assertCorrectShortcutToChooserTargetConversion(List<ShareShortcutInfo> shortcuts, List<ChooserTarget> chooserTargets, int[] expectedOrder, float[] expectedScores) { assertEquals(expectedOrder.length, chooserTargets.size()); for (int i = 0; i < chooserTargets.size(); i++) { ChooserTarget ct = chooserTargets.get(i); ShortcutInfo si = shortcuts.get(expectedOrder[i]).getShortcutInfo(); ComponentName cn = shortcuts.get(expectedOrder[i]).getTargetComponent(); assertEquals(si.getId(), ct.getIntentExtras().getString(Intent.EXTRA_SHORTCUT_ID)); assertEquals(si.getShortLabel(), ct.getTitle()); assertThat(Math.abs(expectedScores[i] - ct.getScore()) < 0.000001, is(true)); assertEquals(cn.flattenToString(), ct.getComponentName().flattenToString()); } } } core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java +11 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.database.Cursor; import android.graphics.Bitmap; import android.net.Uri; Loading Loading @@ -84,6 +85,14 @@ public class ChooserWrapperActivity extends ChooserActivity { return super.getPackageManager(); } @Override public Resources getResources() { if (sOverrides.resources != null) { return sOverrides.resources; } return super.getResources(); } @Override protected Bitmap loadThumbnail(Uri uri, Size size) { if (sOverrides.previewThumbnail != null) { Loading Loading @@ -145,6 +154,7 @@ public class ChooserWrapperActivity extends ChooserActivity { public Bitmap previewThumbnail; public MetricsLogger metricsLogger; public int alternateProfileSetting; public Resources resources; public void reset() { onSafelyStartCallback = null; Loading @@ -157,6 +167,7 @@ public class ChooserWrapperActivity extends ChooserActivity { resolverListController = mock(ResolverListController.class); metricsLogger = mock(MetricsLogger.class); alternateProfileSetting = 0; resources = null; } } } Loading
core/java/com/android/internal/app/ChooserActivity.java +78 −32 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityManager; Loading Loading @@ -729,7 +730,13 @@ public class ChooserActivity extends ResolverActivity { /** * Returns true if app prediction service is defined and the component exists on device. */ private boolean isAppPredictionServiceAvailable() { @VisibleForTesting public boolean isAppPredictionServiceAvailable() { if (getPackageManager().getAppPredictionServicePackageName() == null) { // Default AppPredictionService is not defined. return false; } final String appPredictionServiceName = getString(R.string.config_defaultAppPredictionService); if (appPredictionServiceName == null) { Loading Loading @@ -1584,25 +1591,19 @@ public class ChooserActivity extends ResolverActivity { // ShareShortcutInfos directly. boolean resultMessageSent = false; for (int i = 0; i < driList.size(); i++) { List<ChooserTarget> chooserTargets = new ArrayList<>(); List<ShortcutManager.ShareShortcutInfo> matchingShortcuts = new ArrayList<>(); for (int j = 0; j < resultList.size(); j++) { if (driList.get(i).getResolvedComponentName().equals( resultList.get(j).getTargetComponent())) { ShortcutManager.ShareShortcutInfo shareShortcutInfo = resultList.get(j); // Incoming results are ordered but without a score. Create a score // based on the index in order to be sorted appropriately when joined // with legacy direct share api results. float score = Math.max(1.0f - (0.05f * j), 0.0f); ChooserTarget chooserTarget = convertToChooserTarget(shareShortcutInfo, score); chooserTargets.add(chooserTarget); if (mDirectShareAppTargetCache != null && appTargets != null) { mDirectShareAppTargetCache.put(chooserTarget, appTargets.get(j)); matchingShortcuts.add(resultList.get(j)); } } } if (chooserTargets.isEmpty()) { if (matchingShortcuts.isEmpty()) { continue; } List<ChooserTarget> chooserTargets = convertToChooserTarget( matchingShortcuts, resultList, appTargets, shortcutType); final Message msg = Message.obtain(); msg.what = ChooserHandler.SHORTCUT_MANAGER_SHARE_TARGET_RESULT; msg.obj = new ServiceResultInfo(driList.get(i), chooserTargets, null); Loading Loading @@ -1640,23 +1641,69 @@ public class ChooserActivity extends ResolverActivity { return false; } private ChooserTarget convertToChooserTarget(ShortcutManager.ShareShortcutInfo shareShortcut, float score) { ShortcutInfo shortcutInfo = shareShortcut.getShortcutInfo(); /** * Converts a list of ShareShortcutInfos to ChooserTargets. * @param matchingShortcuts List of shortcuts, all from the same package, that match the current * share intent filter. * @param allShortcuts List of all the shortcuts from all the packages on the device that are * returned for the current sharing action. * @param allAppTargets List of AppTargets. Null if the results are not from prediction service. * @param shortcutType One of the values TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER or * TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE * @return A list of ChooserTargets sorted by score in descending order. */ @VisibleForTesting @NonNull public List<ChooserTarget> convertToChooserTarget( @NonNull List<ShortcutManager.ShareShortcutInfo> matchingShortcuts, @NonNull List<ShortcutManager.ShareShortcutInfo> allShortcuts, @Nullable List<AppTarget> allAppTargets, @ShareTargetType int shortcutType) { // A set of distinct scores for the matched shortcuts. We use index of a rank in the sorted // list instead of the actual rank value when converting a rank to a score. List<Integer> scoreList = new ArrayList<>(); if (shortcutType == TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER) { for (int i = 0; i < matchingShortcuts.size(); i++) { int shortcutRank = matchingShortcuts.get(i).getShortcutInfo().getRank(); if (!scoreList.contains(shortcutRank)) { scoreList.add(shortcutRank); } } Collections.sort(scoreList); } List<ChooserTarget> chooserTargetList = new ArrayList<>(matchingShortcuts.size()); for (int i = 0; i < matchingShortcuts.size(); i++) { ShortcutInfo shortcutInfo = matchingShortcuts.get(i).getShortcutInfo(); int indexInAllShortcuts = allShortcuts.indexOf(matchingShortcuts.get(i)); float score; if (shortcutType == TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE) { // Incoming results are ordered. Create a score based on index in the original list. score = Math.max(1.0f - (0.01f * indexInAllShortcuts), 0.0f); } else { // Create a score based on the rank of the shortcut. int rankIndex = scoreList.indexOf(shortcutInfo.getRank()); score = Math.max(1.0f - (0.01f * rankIndex), 0.0f); } Bundle extras = new Bundle(); extras.putString(Intent.EXTRA_SHORTCUT_ID, shortcutInfo.getId()); return new ChooserTarget( // The name of this target. shortcutInfo.getShortLabel(), // Don't load the icon until it is selected to be shown null, // The ranking score for this target (0.0-1.0); the system will omit items with low // scores when there are too many Direct Share items. score, // The name of the component to be launched if this target is chosen. shareShortcut.getTargetComponent().clone(), // The extra values here will be merged into the Intent when this target is chosen. extras); ChooserTarget chooserTarget = new ChooserTarget(shortcutInfo.getShortLabel(), null, // Icon will be loaded later if this target is selected to be shown. score, matchingShortcuts.get(i).getTargetComponent().clone(), extras); chooserTargetList.add(chooserTarget); if (mDirectShareAppTargetCache != null && allAppTargets != null) { mDirectShareAppTargetCache.put(chooserTarget, allAppTargets.get(indexInAllShortcuts)); } } // Sort ChooserTargets by score in descending order Comparator<ChooserTarget> byScore = (ChooserTarget a, ChooserTarget b) -> -Float.compare(a.getScore(), b.getScore()); Collections.sort(chooserTargetList, byScore); return chooserTargetList; } private String convertServiceName(String packageName, String serviceName) { Loading Loading @@ -1748,8 +1795,7 @@ public class ChooserActivity extends ResolverActivity { if (!mIsAppPredictorComponentAvailable) { return null; } if (mAppPredictor == null && getPackageManager().getAppPredictionServicePackageName() != null) { if (mAppPredictor == null) { final IntentFilter filter = getTargetIntentFilter(); Bundle extras = new Bundle(); extras.putParcelable(APP_PREDICTION_INTENT_FILTER_KEY, filter); Loading
core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java +144 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; Loading @@ -51,6 +52,8 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager.ShareShortcutInfo; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.Canvas; Loading Loading @@ -807,6 +810,108 @@ public class ChooserActivityTest { is(testBaseScore * SHORTCUT_TARGET_SCORE_BOOST)); } /** * The case when AppPrediction service is not defined in PackageManager is already covered * as a test parameter {@link ChooserActivityTest#packageManagers}. This test is checking the * case when the prediction service is defined but the component is not available on the device. */ @Test public void testIsAppPredictionServiceAvailable() { Intent sendIntent = createSendTextIntent(); List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(), Mockito.anyBoolean(), Mockito.isA(List.class))).thenReturn(resolvedComponentInfos); final ChooserWrapperActivity activity = mActivityRule .launchActivity(Intent.createChooser(sendIntent, null)); waitForIdle(); if (activity.getPackageManager().getAppPredictionServicePackageName() == null) { assertThat(activity.isAppPredictionServiceAvailable(), is(false)); } else { assertThat(activity.isAppPredictionServiceAvailable(), is(true)); sOverrides.resources = Mockito.spy(activity.getResources()); when(sOverrides.resources.getString(R.string.config_defaultAppPredictionService)) .thenReturn("ComponentNameThatDoesNotExist"); assertThat(activity.isAppPredictionServiceAvailable(), is(false)); } } @Test public void testConvertToChooserTarget_predictionService() { Intent sendIntent = createSendTextIntent(); List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(), Mockito.anyBoolean(), Mockito.isA(List.class))).thenReturn(resolvedComponentInfos); final ChooserWrapperActivity activity = mActivityRule .launchActivity(Intent.createChooser(sendIntent, null)); waitForIdle(); List<ShareShortcutInfo> shortcuts = createShortcuts(activity); int[] expectedOrderAllShortcuts = {0, 1, 2, 3}; float[] expectedScoreAllShortcuts = {1.0f, 0.99f, 0.98f, 0.97f}; List<ChooserTarget> chooserTargets = activity.convertToChooserTarget(shortcuts, shortcuts, null, TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE); assertCorrectShortcutToChooserTargetConversion(shortcuts, chooserTargets, expectedOrderAllShortcuts, expectedScoreAllShortcuts); List<ShareShortcutInfo> subset = new ArrayList<>(); subset.add(shortcuts.get(1)); subset.add(shortcuts.get(2)); subset.add(shortcuts.get(3)); int[] expectedOrderSubset = {1, 2, 3}; float[] expectedScoreSubset = {0.99f, 0.98f, 0.97f}; chooserTargets = activity.convertToChooserTarget(subset, shortcuts, null, TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE); assertCorrectShortcutToChooserTargetConversion(shortcuts, chooserTargets, expectedOrderSubset, expectedScoreSubset); } @Test public void testConvertToChooserTarget_shortcutManager() { Intent sendIntent = createSendTextIntent(); List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(), Mockito.anyBoolean(), Mockito.isA(List.class))).thenReturn(resolvedComponentInfos); final ChooserWrapperActivity activity = mActivityRule .launchActivity(Intent.createChooser(sendIntent, null)); waitForIdle(); List<ShareShortcutInfo> shortcuts = createShortcuts(activity); int[] expectedOrderAllShortcuts = {2, 0, 3, 1}; float[] expectedScoreAllShortcuts = {1.0f, 0.99f, 0.99f, 0.98f}; List<ChooserTarget> chooserTargets = activity.convertToChooserTarget(shortcuts, shortcuts, null, TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER); assertCorrectShortcutToChooserTargetConversion(shortcuts, chooserTargets, expectedOrderAllShortcuts, expectedScoreAllShortcuts); List<ShareShortcutInfo> subset = new ArrayList<>(); subset.add(shortcuts.get(1)); subset.add(shortcuts.get(2)); subset.add(shortcuts.get(3)); int[] expectedOrderSubset = {2, 3, 1}; float[] expectedScoreSubset = {1.0f, 0.99f, 0.98f}; chooserTargets = activity.convertToChooserTarget(subset, shortcuts, null, TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER); assertCorrectShortcutToChooserTargetConversion(shortcuts, chooserTargets, expectedOrderSubset, expectedScoreSubset); } // This test is too long and too slow and should not be taken as an example for future tests. @Test public void testDirectTargetSelectionLogging() throws InterruptedException { Loading Loading @@ -1103,4 +1208,43 @@ public class ChooserActivityTest { return bitmap; } private List<ShareShortcutInfo> createShortcuts(Context context) { Intent testIntent = new Intent("TestIntent"); List<ShareShortcutInfo> shortcuts = new ArrayList<>(); shortcuts.add(new ShareShortcutInfo( new ShortcutInfo.Builder(context, "shortcut1") .setIntent(testIntent).setShortLabel("label1").setRank(3).build(), // 0 2 new ComponentName("package1", "class1"))); shortcuts.add(new ShareShortcutInfo( new ShortcutInfo.Builder(context, "shortcut2") .setIntent(testIntent).setShortLabel("label2").setRank(7).build(), // 1 3 new ComponentName("package2", "class2"))); shortcuts.add(new ShareShortcutInfo( new ShortcutInfo.Builder(context, "shortcut3") .setIntent(testIntent).setShortLabel("label3").setRank(1).build(), // 2 0 new ComponentName("package3", "class3"))); shortcuts.add(new ShareShortcutInfo( new ShortcutInfo.Builder(context, "shortcut4") .setIntent(testIntent).setShortLabel("label4").setRank(3).build(), // 3 2 new ComponentName("package4", "class4"))); return shortcuts; } private void assertCorrectShortcutToChooserTargetConversion(List<ShareShortcutInfo> shortcuts, List<ChooserTarget> chooserTargets, int[] expectedOrder, float[] expectedScores) { assertEquals(expectedOrder.length, chooserTargets.size()); for (int i = 0; i < chooserTargets.size(); i++) { ChooserTarget ct = chooserTargets.get(i); ShortcutInfo si = shortcuts.get(expectedOrder[i]).getShortcutInfo(); ComponentName cn = shortcuts.get(expectedOrder[i]).getTargetComponent(); assertEquals(si.getId(), ct.getIntentExtras().getString(Intent.EXTRA_SHORTCUT_ID)); assertEquals(si.getShortLabel(), ct.getTitle()); assertThat(Math.abs(expectedScores[i] - ct.getScore()) < 0.000001, is(true)); assertEquals(cn.flattenToString(), ct.getComponentName().flattenToString()); } } }
core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java +11 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.database.Cursor; import android.graphics.Bitmap; import android.net.Uri; Loading Loading @@ -84,6 +85,14 @@ public class ChooserWrapperActivity extends ChooserActivity { return super.getPackageManager(); } @Override public Resources getResources() { if (sOverrides.resources != null) { return sOverrides.resources; } return super.getResources(); } @Override protected Bitmap loadThumbnail(Uri uri, Size size) { if (sOverrides.previewThumbnail != null) { Loading Loading @@ -145,6 +154,7 @@ public class ChooserWrapperActivity extends ChooserActivity { public Bitmap previewThumbnail; public MetricsLogger metricsLogger; public int alternateProfileSetting; public Resources resources; public void reset() { onSafelyStartCallback = null; Loading @@ -157,6 +167,7 @@ public class ChooserWrapperActivity extends ChooserActivity { resolverListController = mock(ResolverListController.class); metricsLogger = mock(MetricsLogger.class); alternateProfileSetting = 0; resources = null; } } }