Merge changes I41e08b86,I7760f37d into qt-qpr1-dev

am: 30e495d0c4

Change-Id: Iae876b13f07a0bfe55baff58ca672d93a0f461e3
This commit is contained in:
Mehdi Alizadeh
2019-09-16 16:31:24 -07:00
committed by android-build-merger
3 changed files with 233 additions and 32 deletions

View File

@@ -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;
@@ -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) {
@@ -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);
@@ -1640,23 +1641,69 @@ public class ChooserActivity extends ResolverActivity {
return false;
}
private ChooserTarget convertToChooserTarget(ShortcutManager.ShareShortcutInfo shareShortcut,
float score) {
ShortcutInfo shortcutInfo = shareShortcut.getShortcutInfo();
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);
/**
* 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());
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) {
@@ -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);

View File

@@ -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;
@@ -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;
@@ -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 {
@@ -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());
}
}
}

View File

@@ -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;
@@ -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) {
@@ -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;
@@ -157,6 +167,7 @@ public class ChooserWrapperActivity extends ChooserActivity {
resolverListController = mock(ResolverListController.class);
metricsLogger = mock(MetricsLogger.class);
alternateProfileSetting = 0;
resources = null;
}
}
}