Surface DS targets as per their own score and ranking, remove customized ranking logic (max shortcuts count limit per app, app share adjustment).
This is guarded by the flag "apply_sharing_app_limits_in_sysui". Bug: 182146792 Test: verify on local phone Test: atest ChooserActivityTest Change-Id: Ic03395343432015400f37299e5748932d2bd9eaa
This commit is contained in:
@@ -850,9 +850,7 @@ public class ChooserActivity extends ResolverActivity implements
|
|||||||
final List<ShortcutManager.ShareShortcutInfo> shareShortcutInfos =
|
final List<ShortcutManager.ShareShortcutInfo> shareShortcutInfos =
|
||||||
new ArrayList<>();
|
new ArrayList<>();
|
||||||
|
|
||||||
// Separate ChooserTargets ranking scores and ranked Shortcuts.
|
|
||||||
List<AppTarget> shortcutResults = new ArrayList<>();
|
List<AppTarget> shortcutResults = new ArrayList<>();
|
||||||
List<AppTarget> chooserTargetScores = new ArrayList<>();
|
|
||||||
for (AppTarget appTarget : resultList) {
|
for (AppTarget appTarget : resultList) {
|
||||||
if (appTarget.getShortcutInfo() == null) {
|
if (appTarget.getShortcutInfo() == null) {
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -33,9 +33,9 @@ import android.graphics.drawable.Drawable;
|
|||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
|
import android.provider.DeviceConfig;
|
||||||
import android.service.chooser.ChooserTarget;
|
import android.service.chooser.ChooserTarget;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
@@ -46,14 +46,13 @@ import com.android.internal.app.chooser.DisplayResolveInfo;
|
|||||||
import com.android.internal.app.chooser.MultiDisplayResolveInfo;
|
import com.android.internal.app.chooser.MultiDisplayResolveInfo;
|
||||||
import com.android.internal.app.chooser.SelectableTargetInfo;
|
import com.android.internal.app.chooser.SelectableTargetInfo;
|
||||||
import com.android.internal.app.chooser.TargetInfo;
|
import com.android.internal.app.chooser.TargetInfo;
|
||||||
|
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class ChooserListAdapter extends ResolverListAdapter {
|
public class ChooserListAdapter extends ResolverListAdapter {
|
||||||
private static final String TAG = "ChooserListAdapter";
|
private static final String TAG = "ChooserListAdapter";
|
||||||
@@ -70,8 +69,6 @@ public class ChooserListAdapter extends ResolverListAdapter {
|
|||||||
|
|
||||||
private static final int MAX_SUGGESTED_APP_TARGETS = 4;
|
private static final int MAX_SUGGESTED_APP_TARGETS = 4;
|
||||||
private static final int MAX_CHOOSER_TARGETS_PER_APP = 2;
|
private static final int MAX_CHOOSER_TARGETS_PER_APP = 2;
|
||||||
private static final int MAX_SERVICE_TARGET_APP = 8;
|
|
||||||
private static final int DEFAULT_DIRECT_SHARE_RANKING_SCORE = 1000;
|
|
||||||
|
|
||||||
/** {@link #getBaseScore} */
|
/** {@link #getBaseScore} */
|
||||||
public static final float CALLER_TARGET_SCORE_BOOST = 900.f;
|
public static final float CALLER_TARGET_SCORE_BOOST = 900.f;
|
||||||
@@ -85,17 +82,11 @@ public class ChooserListAdapter extends ResolverListAdapter {
|
|||||||
|
|
||||||
private int mNumShortcutResults = 0;
|
private int mNumShortcutResults = 0;
|
||||||
private Map<DisplayResolveInfo, LoadIconTask> mIconLoaders = new HashMap<>();
|
private Map<DisplayResolveInfo, LoadIconTask> mIconLoaders = new HashMap<>();
|
||||||
|
private boolean mApplySharingAppLimits;
|
||||||
|
|
||||||
// Reserve spots for incoming direct share targets by adding placeholders
|
// Reserve spots for incoming direct share targets by adding placeholders
|
||||||
private ChooserTargetInfo
|
private ChooserTargetInfo
|
||||||
mPlaceHolderTargetInfo = new ChooserActivity.PlaceHolderTargetInfo();
|
mPlaceHolderTargetInfo = new ChooserActivity.PlaceHolderTargetInfo();
|
||||||
private int mValidServiceTargetsNum = 0;
|
|
||||||
private int mAvailableServiceTargetsNum = 0;
|
|
||||||
private final Map<ComponentName, Pair<List<ChooserTargetInfo>, Integer>>
|
|
||||||
mParkingDirectShareTargets = new HashMap<>();
|
|
||||||
private final Map<ComponentName, Map<String, Integer>> mChooserTargetScores = new HashMap<>();
|
|
||||||
private Set<ComponentName> mPendingChooserTargetService = new HashSet<>();
|
|
||||||
private Set<ComponentName> mShortcutComponents = new HashSet<>();
|
|
||||||
private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>();
|
private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>();
|
||||||
private final List<DisplayResolveInfo> mCallerTargets = new ArrayList<>();
|
private final List<DisplayResolveInfo> mCallerTargets = new ArrayList<>();
|
||||||
|
|
||||||
@@ -174,6 +165,10 @@ public class ChooserListAdapter extends ResolverListAdapter {
|
|||||||
if (mCallerTargets.size() == MAX_SUGGESTED_APP_TARGETS) break;
|
if (mCallerTargets.size() == MAX_SUGGESTED_APP_TARGETS) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mApplySharingAppLimits = DeviceConfig.getBoolean(
|
||||||
|
DeviceConfig.NAMESPACE_SYSTEMUI,
|
||||||
|
SystemUiDeviceConfigFlags.APPLY_SHARING_APP_LIMITS_IN_SYSUI,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
AppPredictor getAppPredictor() {
|
AppPredictor getAppPredictor() {
|
||||||
@@ -209,10 +204,6 @@ public class ChooserListAdapter extends ResolverListAdapter {
|
|||||||
private void createPlaceHolders() {
|
private void createPlaceHolders() {
|
||||||
mNumShortcutResults = 0;
|
mNumShortcutResults = 0;
|
||||||
mServiceTargets.clear();
|
mServiceTargets.clear();
|
||||||
mValidServiceTargetsNum = 0;
|
|
||||||
mParkingDirectShareTargets.clear();
|
|
||||||
mPendingChooserTargetService.clear();
|
|
||||||
mShortcutComponents.clear();
|
|
||||||
for (int i = 0; i < mChooserListCommunicator.getMaxRankedTargets(); i++) {
|
for (int i = 0; i < mChooserListCommunicator.getMaxRankedTargets(); i++) {
|
||||||
mServiceTargets.add(mPlaceHolderTargetInfo);
|
mServiceTargets.add(mPlaceHolderTargetInfo);
|
||||||
}
|
}
|
||||||
@@ -508,25 +499,27 @@ public class ChooserListAdapter extends ResolverListAdapter {
|
|||||||
if (targets.size() == 0) {
|
if (targets.size() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final float baseScore = getBaseScore(origTarget, targetType);
|
final float baseScore = getBaseScore(origTarget, targetType);
|
||||||
Collections.sort(targets, mBaseTargetComparator);
|
Collections.sort(targets, mBaseTargetComparator);
|
||||||
|
|
||||||
final boolean isShortcutResult =
|
final boolean isShortcutResult =
|
||||||
(targetType == TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER
|
(targetType == TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER
|
||||||
|| targetType == TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE);
|
|| targetType == TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE);
|
||||||
final int maxTargets = isShortcutResult ? mMaxShortcutTargetsPerApp
|
final int maxTargets = isShortcutResult ? mMaxShortcutTargetsPerApp
|
||||||
: MAX_CHOOSER_TARGETS_PER_APP;
|
: MAX_CHOOSER_TARGETS_PER_APP;
|
||||||
|
final int targetsLimit = mApplySharingAppLimits ? Math.min(targets.size(), maxTargets)
|
||||||
|
: targets.size();
|
||||||
float lastScore = 0;
|
float lastScore = 0;
|
||||||
boolean shouldNotify = false;
|
boolean shouldNotify = false;
|
||||||
for (int i = 0, count = Math.min(targets.size(), maxTargets); i < count; i++) {
|
for (int i = 0, count = targetsLimit; i < count; i++) {
|
||||||
final ChooserTarget target = targets.get(i);
|
final ChooserTarget target = targets.get(i);
|
||||||
float targetScore = target.getScore();
|
float targetScore = target.getScore();
|
||||||
targetScore *= baseScore;
|
if (mApplySharingAppLimits) {
|
||||||
if (i > 0 && targetScore >= lastScore) {
|
targetScore *= baseScore;
|
||||||
// Apply a decay so that the top app can't crowd out everything else.
|
if (i > 0 && targetScore >= lastScore) {
|
||||||
// This incents ChooserTargetServices to define what's truly better.
|
// Apply a decay so that the top app can't crowd out everything else.
|
||||||
targetScore = lastScore * 0.95f;
|
// This incents ChooserTargetServices to define what's truly better.
|
||||||
|
targetScore = lastScore * 0.95f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
UserHandle userHandle = getUserHandle();
|
UserHandle userHandle = getUserHandle();
|
||||||
Context contextAsUser = mContext.createContextAsUser(userHandle, 0 /* flags */);
|
Context contextAsUser = mContext.createContextAsUser(userHandle, 0 /* flags */);
|
||||||
@@ -544,7 +537,8 @@ public class ChooserListAdapter extends ResolverListAdapter {
|
|||||||
Log.d(TAG, " => " + target.toString() + " score=" + targetScore
|
Log.d(TAG, " => " + target.toString() + " score=" + targetScore
|
||||||
+ " base=" + target.getScore()
|
+ " base=" + target.getScore()
|
||||||
+ " lastScore=" + lastScore
|
+ " lastScore=" + lastScore
|
||||||
+ " baseScore=" + baseScore);
|
+ " baseScore=" + baseScore
|
||||||
|
+ " applyAppLimit=" + mApplySharingAppLimits);
|
||||||
}
|
}
|
||||||
|
|
||||||
lastScore = targetScore;
|
lastScore = targetScore;
|
||||||
@@ -580,16 +574,11 @@ public class ChooserListAdapter extends ResolverListAdapter {
|
|||||||
if (target == null) {
|
if (target == null) {
|
||||||
return CALLER_TARGET_SCORE_BOOST;
|
return CALLER_TARGET_SCORE_BOOST;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetType == TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE) {
|
|
||||||
return SHORTCUT_TARGET_SCORE_BOOST;
|
|
||||||
}
|
|
||||||
|
|
||||||
float score = super.getScore(target);
|
float score = super.getScore(target);
|
||||||
if (targetType == TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER) {
|
if (targetType == TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER
|
||||||
|
|| targetType == TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE) {
|
||||||
return score * SHORTCUT_TARGET_SCORE_BOOST;
|
return score * SHORTCUT_TARGET_SCORE_BOOST;
|
||||||
}
|
}
|
||||||
|
|
||||||
return score;
|
return score;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -479,6 +479,14 @@ public final class SystemUiDeviceConfigFlags {
|
|||||||
*/
|
*/
|
||||||
public static final String SHARE_USE_SERVICE_TARGETS = "share_use_service_targets";
|
public static final String SHARE_USE_SERVICE_TARGETS = "share_use_service_targets";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (boolean) If true, SysUI provides guardrails for app usage of Direct Share by enforcing
|
||||||
|
* limits on number of targets per app & adjusting scores for apps providing many targets. If
|
||||||
|
* false, this step is skipped. This should be true unless the ranking provider configured by
|
||||||
|
* [some other flag] is expected to manage these incentives.
|
||||||
|
*/
|
||||||
|
public static final String APPLY_SHARING_APP_LIMITS_IN_SYSUI =
|
||||||
|
"apply_sharing_app_limits_in_sysui";
|
||||||
|
|
||||||
private SystemUiDeviceConfigFlags() {
|
private SystemUiDeviceConfigFlags() {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -154,8 +154,8 @@ public class ChooserActivityTest {
|
|||||||
sOverrides.reset();
|
sOverrides.reset();
|
||||||
sOverrides.createPackageManager = mPackageManagerOverride;
|
sOverrides.createPackageManager = mPackageManagerOverride;
|
||||||
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
|
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
|
||||||
SystemUiDeviceConfigFlags.APPEND_DIRECT_SHARE_ENABLED,
|
SystemUiDeviceConfigFlags.APPLY_SHARING_APP_LIMITS_IN_SYSUI,
|
||||||
Boolean.toString(false),
|
Boolean.toString(true),
|
||||||
true /* makeDefault*/);
|
true /* makeDefault*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1017,7 +1017,7 @@ public class ChooserActivityTest {
|
|||||||
assertThat(adapter.getBaseScore(testDri, TARGET_TYPE_DEFAULT), is(testBaseScore));
|
assertThat(adapter.getBaseScore(testDri, TARGET_TYPE_DEFAULT), is(testBaseScore));
|
||||||
assertThat(adapter.getBaseScore(testDri, TARGET_TYPE_CHOOSER_TARGET), is(testBaseScore));
|
assertThat(adapter.getBaseScore(testDri, TARGET_TYPE_CHOOSER_TARGET), is(testBaseScore));
|
||||||
assertThat(adapter.getBaseScore(testDri, TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE),
|
assertThat(adapter.getBaseScore(testDri, TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE),
|
||||||
is(SHORTCUT_TARGET_SCORE_BOOST));
|
is(testBaseScore * SHORTCUT_TARGET_SCORE_BOOST));
|
||||||
assertThat(adapter.getBaseScore(testDri, TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER),
|
assertThat(adapter.getBaseScore(testDri, TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER),
|
||||||
is(testBaseScore * SHORTCUT_TARGET_SCORE_BOOST));
|
is(testBaseScore * SHORTCUT_TARGET_SCORE_BOOST));
|
||||||
}
|
}
|
||||||
@@ -1262,6 +1262,126 @@ public class ChooserActivityTest {
|
|||||||
.getAllValues().get(2).getTaggedData(MetricsEvent.FIELD_RANKED_POSITION), is(0));
|
.getAllValues().get(2).getTaggedData(MetricsEvent.FIELD_RANKED_POSITION), is(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testShortcutTargetWithApplyAppLimits() throws InterruptedException {
|
||||||
|
// Set up resources
|
||||||
|
sOverrides.resources = Mockito.spy(
|
||||||
|
InstrumentationRegistry.getInstrumentation().getContext().getResources());
|
||||||
|
when(sOverrides.resources.getInteger(R.integer.config_maxShortcutTargetsPerApp))
|
||||||
|
.thenReturn(1);
|
||||||
|
Intent sendIntent = createSendTextIntent();
|
||||||
|
// We need app targets for direct targets to get displayed
|
||||||
|
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
|
||||||
|
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
|
||||||
|
Mockito.anyBoolean(),
|
||||||
|
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
|
||||||
|
// Create direct share target
|
||||||
|
List<ChooserTarget> serviceTargets = createDirectShareTargets(2,
|
||||||
|
resolvedComponentInfos.get(0).getResolveInfoAt(0).activityInfo.packageName);
|
||||||
|
ResolveInfo ri = ResolverDataProvider.createResolveInfo(3, 0);
|
||||||
|
|
||||||
|
// Start activity
|
||||||
|
final ChooserWrapperActivity activity = mActivityRule
|
||||||
|
.launchActivity(Intent.createChooser(sendIntent, null));
|
||||||
|
|
||||||
|
// Insert the direct share target
|
||||||
|
Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos = new HashMap<>();
|
||||||
|
List<ShareShortcutInfo> shortcutInfos = createShortcuts(activity);
|
||||||
|
directShareToShortcutInfos.put(serviceTargets.get(0),
|
||||||
|
shortcutInfos.get(0).getShortcutInfo());
|
||||||
|
directShareToShortcutInfos.put(serviceTargets.get(1),
|
||||||
|
shortcutInfos.get(1).getShortcutInfo());
|
||||||
|
InstrumentationRegistry.getInstrumentation().runOnMainSync(
|
||||||
|
() -> activity.getAdapter().addServiceResults(
|
||||||
|
activity.createTestDisplayResolveInfo(sendIntent,
|
||||||
|
ri,
|
||||||
|
"testLabel",
|
||||||
|
"testInfo",
|
||||||
|
sendIntent,
|
||||||
|
/* resolveInfoPresentationGetter */ null),
|
||||||
|
serviceTargets,
|
||||||
|
TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE,
|
||||||
|
directShareToShortcutInfos,
|
||||||
|
List.of())
|
||||||
|
);
|
||||||
|
// Thread.sleep shouldn't be a thing in an integration test but it's
|
||||||
|
// necessary here because of the way the code is structured
|
||||||
|
// TODO: restructure the tests b/129870719
|
||||||
|
Thread.sleep(ChooserActivity.LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS);
|
||||||
|
|
||||||
|
assertThat("Chooser should have 3 targets (2 apps, 1 direct)",
|
||||||
|
activity.getAdapter().getCount(), is(3));
|
||||||
|
assertThat("Chooser should have exactly one selectable direct target",
|
||||||
|
activity.getAdapter().getSelectableServiceTargetCount(), is(1));
|
||||||
|
assertThat("The resolver info must match the resolver info used to create the target",
|
||||||
|
activity.getAdapter().getItem(0).getResolveInfo(), is(ri));
|
||||||
|
assertThat("The display label must match",
|
||||||
|
activity.getAdapter().getItem(0).getDisplayLabel(), is("testTitle0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testShortcutTargetWithoutApplyAppLimits() throws InterruptedException {
|
||||||
|
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
|
||||||
|
SystemUiDeviceConfigFlags.APPLY_SHARING_APP_LIMITS_IN_SYSUI,
|
||||||
|
Boolean.toString(false),
|
||||||
|
true /* makeDefault*/);
|
||||||
|
// Set up resources
|
||||||
|
sOverrides.resources = Mockito.spy(
|
||||||
|
InstrumentationRegistry.getInstrumentation().getContext().getResources());
|
||||||
|
when(sOverrides.resources.getInteger(R.integer.config_maxShortcutTargetsPerApp))
|
||||||
|
.thenReturn(1);
|
||||||
|
Intent sendIntent = createSendTextIntent();
|
||||||
|
// We need app targets for direct targets to get displayed
|
||||||
|
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
|
||||||
|
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
|
||||||
|
Mockito.anyBoolean(),
|
||||||
|
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
|
||||||
|
// Create direct share target
|
||||||
|
List<ChooserTarget> serviceTargets = createDirectShareTargets(2,
|
||||||
|
resolvedComponentInfos.get(0).getResolveInfoAt(0).activityInfo.packageName);
|
||||||
|
ResolveInfo ri = ResolverDataProvider.createResolveInfo(3, 0);
|
||||||
|
|
||||||
|
// Start activity
|
||||||
|
final ChooserWrapperActivity activity = mActivityRule
|
||||||
|
.launchActivity(Intent.createChooser(sendIntent, null));
|
||||||
|
|
||||||
|
// Insert the direct share target
|
||||||
|
Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos = new HashMap<>();
|
||||||
|
List<ShareShortcutInfo> shortcutInfos = createShortcuts(activity);
|
||||||
|
directShareToShortcutInfos.put(serviceTargets.get(0),
|
||||||
|
shortcutInfos.get(0).getShortcutInfo());
|
||||||
|
directShareToShortcutInfos.put(serviceTargets.get(1),
|
||||||
|
shortcutInfos.get(1).getShortcutInfo());
|
||||||
|
InstrumentationRegistry.getInstrumentation().runOnMainSync(
|
||||||
|
() -> activity.getAdapter().addServiceResults(
|
||||||
|
activity.createTestDisplayResolveInfo(sendIntent,
|
||||||
|
ri,
|
||||||
|
"testLabel",
|
||||||
|
"testInfo",
|
||||||
|
sendIntent,
|
||||||
|
/* resolveInfoPresentationGetter */ null),
|
||||||
|
serviceTargets,
|
||||||
|
TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE,
|
||||||
|
directShareToShortcutInfos,
|
||||||
|
List.of())
|
||||||
|
);
|
||||||
|
// Thread.sleep shouldn't be a thing in an integration test but it's
|
||||||
|
// necessary here because of the way the code is structured
|
||||||
|
// TODO: restructure the tests b/129870719
|
||||||
|
Thread.sleep(ChooserActivity.LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS);
|
||||||
|
|
||||||
|
assertThat("Chooser should have 4 targets (2 apps, 2 direct)",
|
||||||
|
activity.getAdapter().getCount(), is(4));
|
||||||
|
assertThat("Chooser should have exactly two selectable direct target",
|
||||||
|
activity.getAdapter().getSelectableServiceTargetCount(), is(2));
|
||||||
|
assertThat("The resolver info must match the resolver info used to create the target",
|
||||||
|
activity.getAdapter().getItem(0).getResolveInfo(), is(ri));
|
||||||
|
assertThat("The display label must match",
|
||||||
|
activity.getAdapter().getItem(0).getDisplayLabel(), is("testTitle0"));
|
||||||
|
assertThat("The display label must match",
|
||||||
|
activity.getAdapter().getItem(1).getDisplayLabel(), is("testTitle1"));
|
||||||
|
}
|
||||||
|
|
||||||
// This test is too long and too slow and should not be taken as an example for future tests.
|
// This test is too long and too slow and should not be taken as an example for future tests.
|
||||||
@Test
|
@Test
|
||||||
public void testDirectTargetLoggingWithAppTargetNotRankedPortrait()
|
public void testDirectTargetLoggingWithAppTargetNotRankedPortrait()
|
||||||
|
|||||||
Reference in New Issue
Block a user