summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--java/src/com/android/intentresolver/chooser/MultiDisplayResolveInfo.java15
-rw-r--r--tests/unit/src/com/android/intentresolver/chooser/TargetInfoTest.kt430
2 files changed, 251 insertions, 194 deletions
diff --git a/java/src/com/android/intentresolver/chooser/MultiDisplayResolveInfo.java b/java/src/com/android/intentresolver/chooser/MultiDisplayResolveInfo.java
index b97e6b45..4fe28384 100644
--- a/java/src/com/android/intentresolver/chooser/MultiDisplayResolveInfo.java
+++ b/java/src/com/android/intentresolver/chooser/MultiDisplayResolveInfo.java
@@ -17,9 +17,11 @@
package com.android.intentresolver.chooser;
import android.app.Activity;
+import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.os.UserHandle;
+import android.util.Log;
import androidx.annotation.Nullable;
@@ -121,6 +123,19 @@ public class MultiDisplayResolveInfo extends DisplayResolveInfo {
}
@Override
+ public ComponentName getResolvedComponentName() {
+ if (hasSelected()) {
+ return mTargetInfos.get(mSelected).getResolvedComponentName();
+ }
+ // It is not expected to have this method be called on an unselected multi-display item.
+ // Call super to preserve the legacy (most likely erroneous) behavior.
+ Log.wtf(
+ "ChooserActivity",
+ "retrieving ResolvedComponentName from an unselected MultiDisplayResolveInfo");
+ return super.getResolvedComponentName();
+ }
+
+ @Override
public boolean startAsUser(Activity activity, Bundle options, UserHandle user) {
return mTargetInfos.get(mSelected).startAsUser(activity, options, user);
}
diff --git a/tests/unit/src/com/android/intentresolver/chooser/TargetInfoTest.kt b/tests/unit/src/com/android/intentresolver/chooser/TargetInfoTest.kt
index a7574c12..b346bee5 100644
--- a/tests/unit/src/com/android/intentresolver/chooser/TargetInfoTest.kt
+++ b/tests/unit/src/com/android/intentresolver/chooser/TargetInfoTest.kt
@@ -24,9 +24,10 @@ import android.content.pm.ActivityInfo
import android.content.pm.ResolveInfo
import android.graphics.drawable.AnimatedVectorDrawable
import android.os.UserHandle
-import android.test.UiThreadTest
+import androidx.test.annotation.UiThreadTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.intentresolver.ResolverDataProvider
+import com.android.intentresolver.ResolverDataProvider.createResolveInfo
import com.android.intentresolver.createChooserTarget
import com.android.intentresolver.createShortcutInfo
import com.android.intentresolver.mock
@@ -41,38 +42,37 @@ import org.mockito.Mockito.times
import org.mockito.Mockito.verify
class TargetInfoTest {
- private val PERSONAL_USER_HANDLE: UserHandle = InstrumentationRegistry
- .getInstrumentation().getTargetContext().getUser()
+ private val PERSONAL_USER_HANDLE: UserHandle =
+ InstrumentationRegistry.getInstrumentation().getTargetContext().getUser()
private val context = InstrumentationRegistry.getInstrumentation().getContext()
@Before
fun setup() {
// SelectableTargetInfo reads DeviceConfig and needs a permission for that.
- InstrumentationRegistry
- .getInstrumentation()
- .getUiAutomation()
+ InstrumentationRegistry.getInstrumentation()
+ .uiAutomation
.adoptShellPermissionIdentity("android.permission.READ_DEVICE_CONFIG")
}
@Test
fun testNewEmptyTargetInfo() {
val info = NotSelectableTargetInfo.newEmptyTargetInfo()
- assertThat(info.isEmptyTargetInfo()).isTrue()
- assertThat(info.isChooserTargetInfo()).isTrue() // From legacy inheritance model.
+ assertThat(info.isEmptyTargetInfo).isTrue()
+ assertThat(info.isChooserTargetInfo).isTrue() // From legacy inheritance model.
assertThat(info.hasDisplayIcon()).isFalse()
assertThat(info.getDisplayIconHolder().getDisplayIcon()).isNull()
}
- @UiThreadTest // AnimatedVectorDrawable needs to start from a thread with a Looper.
+ @UiThreadTest // AnimatedVectorDrawable needs to start from a thread with a Looper.
@Test
fun testNewPlaceholderTargetInfo() {
val info = NotSelectableTargetInfo.newPlaceHolderTargetInfo(context)
assertThat(info.isPlaceHolderTargetInfo).isTrue()
- assertThat(info.isChooserTargetInfo).isTrue() // From legacy inheritance model.
+ assertThat(info.isChooserTargetInfo).isTrue() // From legacy inheritance model.
assertThat(info.hasDisplayIcon()).isTrue()
assertThat(info.displayIconHolder.displayIcon)
- .isInstanceOf(AnimatedVectorDrawable::class.java)
+ .isInstanceOf(AnimatedVectorDrawable::class.java)
// TODO: assert that the animation is pre-started/running (IIUC this requires synchronizing
// with some "render thread" per the `AnimatedVectorDrawable` docs). I believe this is
// possible using `AnimatorTestRule` but I couldn't find any sample usage in Kotlin nor get
@@ -82,34 +82,43 @@ class TargetInfoTest {
@Test
fun testNewSelectableTargetInfo() {
val resolvedIntent = Intent()
- val baseDisplayInfo = DisplayResolveInfo.newDisplayResolveInfo(
- resolvedIntent,
- ResolverDataProvider.createResolveInfo(1, 0, PERSONAL_USER_HANDLE),
- "label",
- "extended info",
- resolvedIntent
- )
- val chooserTarget = createChooserTarget(
- "title", 0.3f, ResolverDataProvider.createComponentName(2), "test_shortcut_id")
+ val baseDisplayInfo =
+ DisplayResolveInfo.newDisplayResolveInfo(
+ resolvedIntent,
+ createResolveInfo(1, 0, PERSONAL_USER_HANDLE),
+ "label",
+ "extended info",
+ resolvedIntent
+ )
+ val chooserTarget =
+ createChooserTarget(
+ "title",
+ 0.3f,
+ ResolverDataProvider.createComponentName(2),
+ "test_shortcut_id"
+ )
val shortcutInfo = createShortcutInfo("id", ResolverDataProvider.createComponentName(3), 3)
- val appTarget = AppTarget(
- AppTargetId("id"),
- chooserTarget.componentName.packageName,
- chooserTarget.componentName.className,
- UserHandle.CURRENT)
-
- val targetInfo = SelectableTargetInfo.newSelectableTargetInfo(
- baseDisplayInfo,
- mock(),
- resolvedIntent,
- chooserTarget,
- 0.1f,
- shortcutInfo,
- appTarget,
- mock(),
- )
+ val appTarget =
+ AppTarget(
+ AppTargetId("id"),
+ chooserTarget.componentName.packageName,
+ chooserTarget.componentName.className,
+ UserHandle.CURRENT
+ )
+
+ val targetInfo =
+ SelectableTargetInfo.newSelectableTargetInfo(
+ baseDisplayInfo,
+ mock(),
+ resolvedIntent,
+ chooserTarget,
+ 0.1f,
+ shortcutInfo,
+ appTarget,
+ mock(),
+ )
assertThat(targetInfo.isSelectableTargetInfo).isTrue()
- assertThat(targetInfo.isChooserTargetInfo).isTrue() // From legacy inheritance model.
+ assertThat(targetInfo.isChooserTargetInfo).isTrue() // From legacy inheritance model.
assertThat(targetInfo.displayResolveInfo).isSameInstanceAs(baseDisplayInfo)
assertThat(targetInfo.chooserTargetComponentName).isEqualTo(chooserTarget.componentName)
assertThat(targetInfo.directShareShortcutId).isEqualTo(shortcutInfo.id)
@@ -121,33 +130,43 @@ class TargetInfoTest {
@Test
fun test_SelectableTargetInfo_componentName_no_source_info() {
- val chooserTarget = createChooserTarget(
- "title", 0.3f, ResolverDataProvider.createComponentName(1), "test_shortcut_id")
+ val chooserTarget =
+ createChooserTarget(
+ "title",
+ 0.3f,
+ ResolverDataProvider.createComponentName(1),
+ "test_shortcut_id"
+ )
val shortcutInfo = createShortcutInfo("id", ResolverDataProvider.createComponentName(2), 3)
- val appTarget = AppTarget(
- AppTargetId("id"),
- chooserTarget.componentName.packageName,
- chooserTarget.componentName.className,
- UserHandle.CURRENT)
+ val appTarget =
+ AppTarget(
+ AppTargetId("id"),
+ chooserTarget.componentName.packageName,
+ chooserTarget.componentName.className,
+ UserHandle.CURRENT
+ )
val pkgName = "org.package"
val className = "MainActivity"
- val backupResolveInfo = ResolveInfo().apply {
- activityInfo = ActivityInfo().apply {
- packageName = pkgName
- name = className
+ val backupResolveInfo =
+ ResolveInfo().apply {
+ activityInfo =
+ ActivityInfo().apply {
+ packageName = pkgName
+ name = className
+ }
}
- }
-
- val targetInfo = SelectableTargetInfo.newSelectableTargetInfo(
- null,
- backupResolveInfo,
- mock(),
- chooserTarget,
- 0.1f,
- shortcutInfo,
- appTarget,
- mock(),
- )
+
+ val targetInfo =
+ SelectableTargetInfo.newSelectableTargetInfo(
+ null,
+ backupResolveInfo,
+ mock(),
+ chooserTarget,
+ 0.1f,
+ shortcutInfo,
+ appTarget,
+ mock(),
+ )
assertThat(targetInfo.resolvedComponentName).isEqualTo(ComponentName(pkgName, className))
}
@@ -156,32 +175,41 @@ class TargetInfoTest {
val resolvedIntent = Intent("DONT_REFINE_ME")
resolvedIntent.putExtra("resolvedIntent", true)
- val baseDisplayInfo = DisplayResolveInfo.newDisplayResolveInfo(
- resolvedIntent,
- ResolverDataProvider.createResolveInfo(1, 0),
- "label",
- "extended info",
- resolvedIntent
- )
- val chooserTarget = createChooserTarget(
- "title", 0.3f, ResolverDataProvider.createComponentName(2), "test_shortcut_id")
+ val baseDisplayInfo =
+ DisplayResolveInfo.newDisplayResolveInfo(
+ resolvedIntent,
+ createResolveInfo(1, 0),
+ "label",
+ "extended info",
+ resolvedIntent
+ )
+ val chooserTarget =
+ createChooserTarget(
+ "title",
+ 0.3f,
+ ResolverDataProvider.createComponentName(2),
+ "test_shortcut_id"
+ )
val shortcutInfo = createShortcutInfo("id", ResolverDataProvider.createComponentName(3), 3)
- val appTarget = AppTarget(
- AppTargetId("id"),
- chooserTarget.componentName.packageName,
- chooserTarget.componentName.className,
- UserHandle.CURRENT)
-
- val targetInfo = SelectableTargetInfo.newSelectableTargetInfo(
- baseDisplayInfo,
- mock(),
- resolvedIntent,
- chooserTarget,
- 0.1f,
- shortcutInfo,
- appTarget,
- mock(),
- )
+ val appTarget =
+ AppTarget(
+ AppTargetId("id"),
+ chooserTarget.componentName.packageName,
+ chooserTarget.componentName.className,
+ UserHandle.CURRENT
+ )
+
+ val targetInfo =
+ SelectableTargetInfo.newSelectableTargetInfo(
+ baseDisplayInfo,
+ mock(),
+ resolvedIntent,
+ chooserTarget,
+ 0.1f,
+ shortcutInfo,
+ appTarget,
+ mock(),
+ )
val refinement = Intent("PROPOSED_REFINEMENT")
assertThat(targetInfo.tryToCloneWithAppliedRefinement(refinement)).isNull()
@@ -193,18 +221,19 @@ class TargetInfoTest {
intent.putExtra(Intent.EXTRA_TEXT, "testing intent sending")
intent.setType("text/plain")
- val resolveInfo = ResolverDataProvider.createResolveInfo(3, 0, PERSONAL_USER_HANDLE)
-
- val targetInfo = DisplayResolveInfo.newDisplayResolveInfo(
- intent,
- resolveInfo,
- "label",
- "extended info",
- intent
- )
- assertThat(targetInfo.isDisplayResolveInfo()).isTrue()
- assertThat(targetInfo.isMultiDisplayResolveInfo()).isFalse()
- assertThat(targetInfo.isChooserTargetInfo()).isFalse()
+ val resolveInfo = createResolveInfo(3, 0, PERSONAL_USER_HANDLE)
+
+ val targetInfo =
+ DisplayResolveInfo.newDisplayResolveInfo(
+ intent,
+ resolveInfo,
+ "label",
+ "extended info",
+ intent
+ )
+ assertThat(targetInfo.isDisplayResolveInfo).isTrue()
+ assertThat(targetInfo.isMultiDisplayResolveInfo).isFalse()
+ assertThat(targetInfo.isChooserTargetInfo).isFalse()
}
@Test
@@ -218,31 +247,30 @@ class TargetInfoTest {
val extraMatch = Intent("REFINE_ME")
extraMatch.putExtra("extraMatch", true)
- val originalInfo = DisplayResolveInfo.newDisplayResolveInfo(
- originalIntent,
- ResolverDataProvider.createResolveInfo(3, 0),
- "label",
- "extended info",
- originalIntent
- )
+ val originalInfo =
+ DisplayResolveInfo.newDisplayResolveInfo(
+ originalIntent,
+ createResolveInfo(3, 0),
+ "label",
+ "extended info",
+ originalIntent
+ )
originalInfo.addAlternateSourceIntent(mismatchedAlternate)
originalInfo.addAlternateSourceIntent(targetAlternate)
originalInfo.addAlternateSourceIntent(extraMatch)
- val refinement = Intent("REFINE_ME") // First match is `targetAlternate`
+ val refinement = Intent("REFINE_ME") // First match is `targetAlternate`
refinement.putExtra("refinement", true)
val refinedResult = checkNotNull(originalInfo.tryToCloneWithAppliedRefinement(refinement))
// Note `DisplayResolveInfo` targets merge refinements directly into their `resolvedIntent`.
- assertThat(refinedResult?.resolvedIntent?.getBooleanExtra("refinement", false)).isTrue()
- assertThat(refinedResult?.resolvedIntent?.getBooleanExtra("targetAlternate", false))
- .isTrue()
+ assertThat(refinedResult.resolvedIntent?.getBooleanExtra("refinement", false)).isTrue()
+ assertThat(refinedResult.resolvedIntent?.getBooleanExtra("targetAlternate", false)).isTrue()
// None of the other source intents got merged in (not even the later one that matched):
- assertThat(refinedResult?.resolvedIntent?.getBooleanExtra("originalIntent", false))
- .isFalse()
- assertThat(refinedResult?.resolvedIntent?.getBooleanExtra("mismatchedAlternate", false))
+ assertThat(refinedResult.resolvedIntent?.getBooleanExtra("originalIntent", false)).isFalse()
+ assertThat(refinedResult.resolvedIntent?.getBooleanExtra("mismatchedAlternate", false))
.isFalse()
- assertThat(refinedResult?.resolvedIntent?.getBooleanExtra("extraMatch", false)).isFalse()
+ assertThat(refinedResult.resolvedIntent?.getBooleanExtra("extraMatch", false)).isFalse()
}
@Test
@@ -252,13 +280,14 @@ class TargetInfoTest {
val mismatchedAlternate = Intent("DOESNT_MATCH")
mismatchedAlternate.putExtra("mismatchedAlternate", true)
- val originalInfo = DisplayResolveInfo.newDisplayResolveInfo(
- originalIntent,
- ResolverDataProvider.createResolveInfo(3, 0),
- "label",
- "extended info",
- originalIntent
- )
+ val originalInfo =
+ DisplayResolveInfo.newDisplayResolveInfo(
+ originalIntent,
+ createResolveInfo(3, 0),
+ "label",
+ "extended info",
+ originalIntent
+ )
originalInfo.addAlternateSourceIntent(mismatchedAlternate)
val refinement = Intent("PROPOSED_REFINEMENT")
@@ -271,41 +300,50 @@ class TargetInfoTest {
intent.putExtra(Intent.EXTRA_TEXT, "testing intent sending")
intent.setType("text/plain")
- val resolveInfo = ResolverDataProvider.createResolveInfo(3, 0, PERSONAL_USER_HANDLE)
- val firstTargetInfo = DisplayResolveInfo.newDisplayResolveInfo(
- intent,
- resolveInfo,
- "label 1",
- "extended info 1",
- intent
- )
- val secondTargetInfo = DisplayResolveInfo.newDisplayResolveInfo(
- intent,
- resolveInfo,
- "label 2",
- "extended info 2",
- intent
- )
-
- val multiTargetInfo = MultiDisplayResolveInfo.newMultiDisplayResolveInfo(
- listOf(firstTargetInfo, secondTargetInfo))
-
- assertThat(multiTargetInfo.isMultiDisplayResolveInfo()).isTrue()
- assertThat(multiTargetInfo.isDisplayResolveInfo()).isTrue() // From legacy inheritance.
- assertThat(multiTargetInfo.isChooserTargetInfo()).isFalse()
-
- assertThat(multiTargetInfo.getExtendedInfo()).isNull()
-
- assertThat(multiTargetInfo.getAllDisplayTargets())
- .containsExactly(firstTargetInfo, secondTargetInfo)
+ val packageName = "org.pkg.app"
+ val componentA = ComponentName(packageName, "org.pkg.app.ActivityA")
+ val componentB = ComponentName(packageName, "org.pkg.app.ActivityB")
+ val resolveInfoA = createResolveInfo(componentA, 0, PERSONAL_USER_HANDLE)
+ val resolveInfoB = createResolveInfo(componentB, 0, PERSONAL_USER_HANDLE)
+ val firstTargetInfo =
+ DisplayResolveInfo.newDisplayResolveInfo(
+ intent,
+ resolveInfoA,
+ "label 1",
+ "extended info 1",
+ intent
+ )
+ val secondTargetInfo =
+ DisplayResolveInfo.newDisplayResolveInfo(
+ intent,
+ resolveInfoB,
+ "label 2",
+ "extended info 2",
+ intent
+ )
+
+ val multiTargetInfo =
+ MultiDisplayResolveInfo.newMultiDisplayResolveInfo(
+ listOf(firstTargetInfo, secondTargetInfo)
+ )
+
+ assertThat(multiTargetInfo.isMultiDisplayResolveInfo).isTrue()
+ assertThat(multiTargetInfo.isDisplayResolveInfo).isTrue() // From legacy inheritance.
+ assertThat(multiTargetInfo.isChooserTargetInfo).isFalse()
+
+ assertThat(multiTargetInfo.extendedInfo).isNull()
+
+ assertThat(multiTargetInfo.allDisplayTargets)
+ .containsExactly(firstTargetInfo, secondTargetInfo)
assertThat(multiTargetInfo.hasSelected()).isFalse()
- assertThat(multiTargetInfo.getSelectedTarget()).isNull()
+ assertThat(multiTargetInfo.selectedTarget).isNull()
multiTargetInfo.setSelected(1)
assertThat(multiTargetInfo.hasSelected()).isTrue()
- assertThat(multiTargetInfo.getSelectedTarget()).isEqualTo(secondTargetInfo)
+ assertThat(multiTargetInfo.selectedTarget).isEqualTo(secondTargetInfo)
+ assertThat(multiTargetInfo.resolvedComponentName).isEqualTo(componentB)
val refined = multiTargetInfo.tryToCloneWithAppliedRefinement(intent)
assertThat(refined).isInstanceOf(MultiDisplayResolveInfo::class.java)
@@ -321,37 +359,40 @@ class TargetInfoTest {
val sendImage = Intent("SEND").apply { type = "image/png" }
val sendUri = Intent("SEND").apply { type = "text/uri" }
- val resolveInfo = ResolverDataProvider.createResolveInfo(1, 0)
-
- val imageOnlyTarget = DisplayResolveInfo.newDisplayResolveInfo(
- sendImage,
- resolveInfo,
- "Send Image",
- "Sends only images",
- sendImage
- )
-
- val textOnlyTarget = DisplayResolveInfo.newDisplayResolveInfo(
- sendUri,
- resolveInfo,
- "Send Text",
- "Sends only text",
- sendUri
- )
-
- val imageOrTextTarget = DisplayResolveInfo.newDisplayResolveInfo(
- sendImage,
- resolveInfo,
- "Send Image or Text",
- "Sends images or text",
- sendImage
- ).apply {
- addAlternateSourceIntent(sendUri)
- }
-
- val multiTargetInfo = MultiDisplayResolveInfo.newMultiDisplayResolveInfo(
- listOf(imageOnlyTarget, textOnlyTarget, imageOrTextTarget)
- )
+ val resolveInfo = createResolveInfo(1, 0)
+
+ val imageOnlyTarget =
+ DisplayResolveInfo.newDisplayResolveInfo(
+ sendImage,
+ resolveInfo,
+ "Send Image",
+ "Sends only images",
+ sendImage
+ )
+
+ val textOnlyTarget =
+ DisplayResolveInfo.newDisplayResolveInfo(
+ sendUri,
+ resolveInfo,
+ "Send Text",
+ "Sends only text",
+ sendUri
+ )
+
+ val imageOrTextTarget =
+ DisplayResolveInfo.newDisplayResolveInfo(
+ sendImage,
+ resolveInfo,
+ "Send Image or Text",
+ "Sends images or text",
+ sendImage
+ )
+ .apply { addAlternateSourceIntent(sendUri) }
+
+ val multiTargetInfo =
+ MultiDisplayResolveInfo.newMultiDisplayResolveInfo(
+ listOf(imageOnlyTarget, textOnlyTarget, imageOrTextTarget)
+ )
multiTargetInfo.setSelected(0)
assertThat(multiTargetInfo.selectedTarget).isEqualTo(imageOnlyTarget)
@@ -370,22 +411,23 @@ class TargetInfoTest {
fun testNewMultiDisplayResolveInfo_tryToCloneWithAppliedRefinement_delegatedToSelectedTarget() {
val refined = Intent("SEND")
val sendImage = Intent("SEND")
- val targetOne = spy(
- DisplayResolveInfo.newDisplayResolveInfo(
- sendImage,
- ResolverDataProvider.createResolveInfo(1, 0),
- "Target One",
- "Target One",
- sendImage
+ val targetOne =
+ spy(
+ DisplayResolveInfo.newDisplayResolveInfo(
+ sendImage,
+ createResolveInfo(1, 0),
+ "Target One",
+ "Target One",
+ sendImage
+ )
)
- )
- val targetTwo = mock<DisplayResolveInfo> {
- whenever(tryToCloneWithAppliedRefinement(any())).thenReturn(this)
- }
-
- val multiTargetInfo = MultiDisplayResolveInfo.newMultiDisplayResolveInfo(
- listOf(targetOne, targetTwo)
- )
+ val targetTwo =
+ mock<DisplayResolveInfo> {
+ whenever(tryToCloneWithAppliedRefinement(any())).thenReturn(this)
+ }
+
+ val multiTargetInfo =
+ MultiDisplayResolveInfo.newMultiDisplayResolveInfo(listOf(targetOne, targetTwo))
multiTargetInfo.setSelected(1)
assertThat(multiTargetInfo.selectedTarget).isEqualTo(targetTwo)