summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
author Andrey Epin <ayepin@google.com> 2023-02-04 06:33:12 +0000
committer Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> 2023-02-04 06:33:12 +0000
commit9f5489d8213f4ff6259c43b076d9538db83180d0 (patch)
tree9a79937c80767008627cd3c4d69ea9a5476c8e30 /java
parentfb86bd0412c7a771ff4e314eaa35fcfc68c6c568 (diff)
parentede473e7fca58b254e4ed2890309458167c68e1f (diff)
Add optional text exclusion from media + text share am: 89697b484b am: ede473e7fc
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/modules/IntentResolver/+/21266095 Change-Id: I99841de8b034150fadd92a30d9d8608dd0234d2b Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
Diffstat (limited to 'java')
-rw-r--r--java/res/layout/chooser_grid_preview_image.xml8
-rw-r--r--java/res/values/strings.xml9
-rw-r--r--java/src/com/android/intentresolver/ChooserActivity.java30
-rw-r--r--java/src/com/android/intentresolver/ChooserContentPreviewUi.java50
-rw-r--r--java/src/com/android/intentresolver/chooser/DisplayResolveInfo.java5
-rw-r--r--java/src/com/android/intentresolver/chooser/MultiDisplayResolveInfo.java5
-rw-r--r--java/src/com/android/intentresolver/chooser/NotSelectableTargetInfo.java7
-rw-r--r--java/src/com/android/intentresolver/chooser/SelectableTargetInfo.java6
-rw-r--r--java/src/com/android/intentresolver/chooser/TargetInfo.java6
-rw-r--r--java/tests/src/com/android/intentresolver/ResolverDataProvider.java27
-rw-r--r--java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java165
11 files changed, 309 insertions, 9 deletions
diff --git a/java/res/layout/chooser_grid_preview_image.xml b/java/res/layout/chooser_grid_preview_image.xml
index 6af0af11..80c12e6c 100644
--- a/java/res/layout/chooser_grid_preview_image.xml
+++ b/java/res/layout/chooser_grid_preview_image.xml
@@ -24,6 +24,14 @@
android:orientation="vertical"
android:background="?android:attr/colorBackground">
+ <CheckBox
+ android:id="@+id/include_text_action"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end"
+ android:layout_marginEnd="@dimen/chooser_edge_margin_normal"
+ android:visibility="gone" />
+
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index 59179504..24604ed3 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -108,4 +108,13 @@
<string name="select_images">Select Images</string>
<!-- Tittle for a button. Launches client-provided content reselection action. -->
<string name="select_text">Select Text</string>
+
+ <!-- Title for a button. Excludes a text from the shared content (a media and a text). -->
+ <string name="exclude_text">Exclude text</string>
+ <!-- Title for a button. Adds back a (previously excluded) text into the shared content. -->
+ <string name="include_text">Include text</string>
+ <!-- Title for a button. Excludes a web link from the shared content (a media and a text). -->
+ <string name="exclude_link">Exclude link</string>
+ <!-- Title for a button. Adds back a (previously excluded) web link into the shared content. -->
+ <string name="include_link">Include link</string>
</resources>
diff --git a/java/src/com/android/intentresolver/ChooserActivity.java b/java/src/com/android/intentresolver/ChooserActivity.java
index e741b06c..3a7d4e68 100644
--- a/java/src/com/android/intentresolver/ChooserActivity.java
+++ b/java/src/com/android/intentresolver/ChooserActivity.java
@@ -262,6 +262,8 @@ public class ChooserActivity extends ResolverActivity implements
private final SparseArray<ProfileRecord> mProfileRecords = new SparseArray<>();
+ private boolean mExcludeSharedText = false;
+
public ChooserActivity() {}
@Override
@@ -771,6 +773,11 @@ public class ChooserActivity extends ResolverActivity implements
? null
: createReselectionRunnable(reselectionAction);
}
+
+ @Override
+ public Consumer<Boolean> getExcludeSharedTextAction() {
+ return (isExcluded) -> mExcludeSharedText = isExcluded;
+ }
};
ViewGroup layout = mChooserContentPreviewUi.displayContentPreview(
@@ -1196,6 +1203,7 @@ public class ChooserActivity extends ResolverActivity implements
}
}
updateModelAndChooserCounts(target);
+ maybeRemoveSharedText(target);
return super.onTargetSelected(target, alwaysCheck);
}
@@ -1384,6 +1392,27 @@ public class ChooserActivity extends ResolverActivity implements
mIsSuccessfullySelected = true;
}
+ private void maybeRemoveSharedText(@androidx.annotation.NonNull TargetInfo targetInfo) {
+ Intent targetIntent = targetInfo.getTargetIntent();
+ if (targetIntent == null) {
+ return;
+ }
+ Intent originalTargetIntent = new Intent(mChooserRequest.getTargetIntent());
+ // Our TargetInfo implementations add associated component to the intent, let's do the same
+ // for the sake of the comparison below.
+ if (targetIntent.getComponent() != null) {
+ originalTargetIntent.setComponent(targetIntent.getComponent());
+ }
+ // Use filterEquals as a way to check that the primary intent is in use (and not an
+ // alternative one). For example, an app is sharing an image and a link with mime type
+ // "image/png" and provides an alternative intent to share only the link with mime type
+ // "text/uri". Should there be a target that accepts only the latter, the alternative intent
+ // will be used and we don't want to exclude the link from it.
+ if (mExcludeSharedText && originalTargetIntent.filterEquals(targetIntent)) {
+ targetIntent.removeExtra(Intent.EXTRA_TEXT);
+ }
+ }
+
private void sendImpressionToAppPredictor(TargetInfo targetInfo, ChooserListAdapter adapter) {
// Send DS target impression info to AppPredictor, only when user chooses app share.
if (targetInfo.isChooserTargetInfo()) {
@@ -1451,6 +1480,7 @@ public class ChooserActivity extends ResolverActivity implements
+ " cannot match refined source intent " + matchingIntent);
} else {
TargetInfo clonedTarget = selectedTarget.cloneFilledIn(matchingIntent, 0);
+ maybeRemoveSharedText(clonedTarget);
if (super.onTargetSelected(clonedTarget, false)) {
updateModelAndChooserCounts(clonedTarget);
finish();
diff --git a/java/src/com/android/intentresolver/ChooserContentPreviewUi.java b/java/src/com/android/intentresolver/ChooserContentPreviewUi.java
index 9bef3553..91abd9d0 100644
--- a/java/src/com/android/intentresolver/ChooserContentPreviewUi.java
+++ b/java/src/com/android/intentresolver/ChooserContentPreviewUi.java
@@ -40,6 +40,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.ViewStub;
import android.view.animation.DecelerateInterpolator;
+import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
@@ -59,6 +60,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.function.Consumer;
import java.util.stream.Collectors;
/**
@@ -100,6 +102,17 @@ public final class ChooserContentPreviewUi {
*/
@Nullable
Runnable getReselectionAction();
+
+ /**
+ * <p>
+ * Creates an exclude-text action that can be called when the user changes shared text
+ * status in the Media + Text preview.
+ * </p>
+ * <p>
+ * <code>true</code> argument value indicates that the text should be excluded.
+ * </p>
+ */
+ Consumer<Boolean> getExcludeSharedTextAction();
}
/**
@@ -222,7 +235,8 @@ public final class ChooserContentPreviewUi {
transitionElementStatusCallback,
contentResolver,
imageClassifier,
- actionRowLayout);
+ actionRowLayout,
+ actionFactory);
break;
case CONTENT_PREVIEW_FILE:
layout = displayFileContentPreview(
@@ -360,7 +374,8 @@ public final class ChooserContentPreviewUi {
TransitionElementStatusCallback transitionElementStatusCallback,
ContentResolver contentResolver,
ImageMimeTypeClassifier imageClassifier,
- @LayoutRes int actionRowLayout) {
+ @LayoutRes int actionRowLayout,
+ ActionFactory actionFactory) {
ViewGroup contentPreviewLayout = (ViewGroup) layoutInflater.inflate(
R.layout.chooser_grid_preview_image, parent, false);
ImagePreviewView imagePreview = inflateImagePreviewView(contentPreviewLayout);
@@ -391,7 +406,8 @@ public final class ChooserContentPreviewUi {
setTextInImagePreviewVisibility(
contentPreviewLayout,
- targetIntent.getCharSequenceExtra(Intent.EXTRA_TEXT));
+ targetIntent.getCharSequenceExtra(Intent.EXTRA_TEXT),
+ actionFactory);
imagePreview.setTransitionElementStatusCallback(transitionElementStatusCallback);
imagePreview.setImages(imageUris, imageLoader);
@@ -399,20 +415,36 @@ public final class ChooserContentPreviewUi {
}
private void setTextInImagePreviewVisibility(
- ViewGroup contentPreview, CharSequence text) {
+ ViewGroup contentPreview, CharSequence text, ActionFactory actionFactory) {
int visibility = mFeatureFlagRepository.isEnabled(Flags.SHARESHEET_IMAGE_AND_TEXT_PREVIEW)
&& !TextUtils.isEmpty(text)
? View.VISIBLE
: View.GONE;
- TextView textView = contentPreview
+ final TextView textView = contentPreview
.requireViewById(com.android.internal.R.id.content_preview_text);
+ CheckBox actionView = contentPreview
+ .requireViewById(R.id.include_text_action);
textView.setVisibility(visibility);
- int linkMask = visibility == View.VISIBLE && HttpUriMatcher.isHttpUri(text.toString())
- ? Linkify.WEB_URLS
- : 0;
- textView.setAutoLinkMask(linkMask);
+ boolean isLink = visibility == View.VISIBLE && HttpUriMatcher.isHttpUri(text.toString());
+ textView.setAutoLinkMask(isLink ? Linkify.WEB_URLS : 0);
textView.setText(text);
+
+ if (visibility == View.VISIBLE) {
+ final int[] actionLabels = isLink
+ ? new int[] { R.string.include_link, R.string.exclude_link }
+ : new int[] { R.string.include_text, R.string.exclude_text };
+ final Consumer<Boolean> shareTextAction = actionFactory.getExcludeSharedTextAction();
+ actionView.setChecked(true);
+ actionView.setText(actionLabels[1]);
+ shareTextAction.accept(false);
+ actionView.setOnCheckedChangeListener((view, isChecked) -> {
+ view.setText(actionLabels[isChecked ? 1 : 0]);
+ textView.setVisibility(isChecked ? View.VISIBLE : View.GONE);
+ shareTextAction.accept(!isChecked);
+ });
+ }
+ actionView.setVisibility(visibility);
}
private static List<ActionRow.Action> createImagePreviewActions(
diff --git a/java/src/com/android/intentresolver/chooser/DisplayResolveInfo.java b/java/src/com/android/intentresolver/chooser/DisplayResolveInfo.java
index 1b729c0e..4bbf59d8 100644
--- a/java/src/com/android/intentresolver/chooser/DisplayResolveInfo.java
+++ b/java/src/com/android/intentresolver/chooser/DisplayResolveInfo.java
@@ -224,6 +224,11 @@ public class DisplayResolveInfo implements TargetInfo {
return false;
}
+ @Override
+ public Intent getTargetIntent() {
+ return mResolvedIntent;
+ }
+
public boolean isSuspended() {
return mIsSuspended;
}
diff --git a/java/src/com/android/intentresolver/chooser/MultiDisplayResolveInfo.java b/java/src/com/android/intentresolver/chooser/MultiDisplayResolveInfo.java
index e4cec887..0d79e5d5 100644
--- a/java/src/com/android/intentresolver/chooser/MultiDisplayResolveInfo.java
+++ b/java/src/com/android/intentresolver/chooser/MultiDisplayResolveInfo.java
@@ -119,4 +119,9 @@ public class MultiDisplayResolveInfo extends DisplayResolveInfo {
public boolean startAsUser(Activity activity, Bundle options, UserHandle user) {
return mTargetInfos.get(mSelected).startAsUser(activity, options, user);
}
+
+ @Override
+ public Intent getTargetIntent() {
+ return mTargetInfos.get(mSelected).getTargetIntent();
+ }
}
diff --git a/java/src/com/android/intentresolver/chooser/NotSelectableTargetInfo.java b/java/src/com/android/intentresolver/chooser/NotSelectableTargetInfo.java
index d6333374..9a2c971f 100644
--- a/java/src/com/android/intentresolver/chooser/NotSelectableTargetInfo.java
+++ b/java/src/com/android/intentresolver/chooser/NotSelectableTargetInfo.java
@@ -16,6 +16,7 @@
package com.android.intentresolver.chooser;
+import android.annotation.Nullable;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
@@ -101,6 +102,12 @@ public abstract class NotSelectableTargetInfo extends ChooserTargetInfo {
return false;
}
+ @Nullable
+ @Override
+ public Intent getTargetIntent() {
+ return null;
+ }
+
public boolean startAsUser(Activity activity, Bundle options, UserHandle user) {
return false;
}
diff --git a/java/src/com/android/intentresolver/chooser/SelectableTargetInfo.java b/java/src/com/android/intentresolver/chooser/SelectableTargetInfo.java
index 3ab50175..ca778233 100644
--- a/java/src/com/android/intentresolver/chooser/SelectableTargetInfo.java
+++ b/java/src/com/android/intentresolver/chooser/SelectableTargetInfo.java
@@ -346,6 +346,12 @@ public final class SelectableTargetInfo extends ChooserTargetInfo {
return mActivityStarter.startAsUser(activity, options, user);
}
+ @Nullable
+ @Override
+ public Intent getTargetIntent() {
+ return mBaseIntentToSend;
+ }
+
@Override
public ResolveInfo getResolveInfo() {
return mResolveInfo;
diff --git a/java/src/com/android/intentresolver/chooser/TargetInfo.java b/java/src/com/android/intentresolver/chooser/TargetInfo.java
index 72dd1b0b..7dcf66b2 100644
--- a/java/src/com/android/intentresolver/chooser/TargetInfo.java
+++ b/java/src/com/android/intentresolver/chooser/TargetInfo.java
@@ -88,6 +88,12 @@ public interface TargetInfo {
Intent getResolvedIntent();
/**
+ * Get the target intent, the one that will be used with one of the <code>start</code> methods.
+ * @return the intent with target will be launced with.
+ */
+ @Nullable Intent getTargetIntent();
+
+ /**
* Get the resolved component name that represents this target. Note that this may not
* be the component that will be directly launched by calling one of the <code>start</code>
* methods provided; this is the component that will be credited with the launch. This may be
diff --git a/java/tests/src/com/android/intentresolver/ResolverDataProvider.java b/java/tests/src/com/android/intentresolver/ResolverDataProvider.java
index fb928e09..6807bfd6 100644
--- a/java/tests/src/com/android/intentresolver/ResolverDataProvider.java
+++ b/java/tests/src/com/android/intentresolver/ResolverDataProvider.java
@@ -41,6 +41,14 @@ public class ResolverDataProvider {
createResolverIntent(i), createResolveInfo(i, UserHandle.USER_CURRENT));
}
+ static ResolverActivity.ResolvedComponentInfo createResolvedComponentInfo(
+ ComponentName componentName, Intent intent) {
+ return new ResolverActivity.ResolvedComponentInfo(
+ componentName,
+ intent,
+ createResolveInfo(componentName, UserHandle.USER_CURRENT));
+ }
+
static ResolverActivity.ResolvedComponentInfo createResolvedComponentInfoWithOtherId(int i) {
return new ResolverActivity.ResolvedComponentInfo(createComponentName(i),
createResolverIntent(i), createResolveInfo(i, USER_SOMEONE_ELSE));
@@ -64,6 +72,13 @@ public class ResolverDataProvider {
return resolveInfo;
}
+ public static ResolveInfo createResolveInfo(ComponentName componentName, int userId) {
+ final ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.activityInfo = createActivityInfo(componentName);
+ resolveInfo.targetUserId = userId;
+ return resolveInfo;
+ }
+
static ActivityInfo createActivityInfo(int i) {
ActivityInfo ai = new ActivityInfo();
ai.name = "activity_name" + i;
@@ -75,6 +90,18 @@ public class ResolverDataProvider {
return ai;
}
+ static ActivityInfo createActivityInfo(ComponentName componentName) {
+ ActivityInfo ai = new ActivityInfo();
+ ai.name = componentName.getClassName();
+ ai.packageName = componentName.getPackageName();
+ ai.enabled = true;
+ ai.exported = true;
+ ai.permission = null;
+ ai.applicationInfo = createApplicationInfo();
+ ai.applicationInfo.packageName = componentName.getPackageName();
+ return ai;
+ }
+
static ApplicationInfo createApplicationInfo() {
ApplicationInfo ai = new ApplicationInfo();
ai.name = "app_name";
diff --git a/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java b/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java
index 249dca62..c90f0b63 100644
--- a/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java
+++ b/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java
@@ -128,6 +128,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -756,6 +757,170 @@ public class UnbundledChooserActivityTest {
}
@Test
+ public void testImagePlusTextSharing_ExcludeText() {
+ ChooserActivityOverrideData.getInstance().featureFlagRepository =
+ new TestFeatureFlagRepository(
+ Collections.singletonMap(Flags.SHARESHEET_IMAGE_AND_TEXT_PREVIEW, true));
+ Intent sendIntent = createSendImageIntent(
+ Uri.parse("android.resource://com.android.frameworks.coretests/"
+ + R.drawable.test320x240));
+ ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
+ ChooserActivityOverrideData.getInstance().isImageType = true;
+ sendIntent.putExtra(Intent.EXTRA_TEXT, "https://google.com/search?q=google");
+
+ List<ResolvedComponentInfo> resolvedComponentInfos = Arrays.asList(
+ ResolverDataProvider.createResolvedComponentInfo(
+ new ComponentName("org.imageviewer", "ImageTarget"),
+ sendIntent),
+ ResolverDataProvider.createResolvedComponentInfo(
+ new ComponentName("org.textviewer", "UriTarget"),
+ new Intent("VIEW_TEXT"))
+ );
+
+ when(
+ ChooserActivityOverrideData
+ .getInstance()
+ .resolverListController
+ .getResolversForIntent(
+ Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class)))
+ .thenReturn(resolvedComponentInfos);
+
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
+ waitForIdle();
+
+ onView(withId(R.id.include_text_action))
+ .check(matches(isDisplayed()))
+ .perform(click());
+ waitForIdle();
+
+ AtomicReference<Intent> launchedIntentRef = new AtomicReference<>();
+ ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
+ launchedIntentRef.set(targetInfo.getTargetIntent());
+ return true;
+ };
+
+ onView(withText(resolvedComponentInfos.get(0).getResolveInfoAt(0).activityInfo.name))
+ .perform(click());
+ waitForIdle();
+ assertThat(launchedIntentRef.get().hasExtra(Intent.EXTRA_TEXT)).isFalse();
+ }
+
+ @Test
+ public void testImagePlusTextSharing_RemoveAndAddBackText() {
+ ChooserActivityOverrideData.getInstance().featureFlagRepository =
+ new TestFeatureFlagRepository(
+ Collections.singletonMap(Flags.SHARESHEET_IMAGE_AND_TEXT_PREVIEW, true));
+ Intent sendIntent = createSendImageIntent(
+ Uri.parse("android.resource://com.android.frameworks.coretests/"
+ + R.drawable.test320x240));
+ ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
+ ChooserActivityOverrideData.getInstance().isImageType = true;
+ final String text = "https://google.com/search?q=google";
+ sendIntent.putExtra(Intent.EXTRA_TEXT, text);
+
+ List<ResolvedComponentInfo> resolvedComponentInfos = Arrays.asList(
+ ResolverDataProvider.createResolvedComponentInfo(
+ new ComponentName("org.imageviewer", "ImageTarget"),
+ sendIntent),
+ ResolverDataProvider.createResolvedComponentInfo(
+ new ComponentName("org.textviewer", "UriTarget"),
+ new Intent("VIEW_TEXT"))
+ );
+
+ when(
+ ChooserActivityOverrideData
+ .getInstance()
+ .resolverListController
+ .getResolversForIntent(
+ Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class)))
+ .thenReturn(resolvedComponentInfos);
+
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
+ waitForIdle();
+
+ onView(withId(R.id.include_text_action))
+ .check(matches(isDisplayed()))
+ .perform(click());
+ waitForIdle();
+ onView(withId(R.id.include_text_action))
+ .perform(click());
+ waitForIdle();
+
+ AtomicReference<Intent> launchedIntentRef = new AtomicReference<>();
+ ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
+ launchedIntentRef.set(targetInfo.getTargetIntent());
+ return true;
+ };
+
+ onView(withText(resolvedComponentInfos.get(0).getResolveInfoAt(0).activityInfo.name))
+ .perform(click());
+ waitForIdle();
+ assertThat(launchedIntentRef.get().getStringExtra(Intent.EXTRA_TEXT)).isEqualTo(text);
+ }
+
+ @Test
+ public void testImagePlusTextSharing_TextExclusionDoesNotAffectAlternativeIntent() {
+ ChooserActivityOverrideData.getInstance().featureFlagRepository =
+ new TestFeatureFlagRepository(
+ Collections.singletonMap(Flags.SHARESHEET_IMAGE_AND_TEXT_PREVIEW, true));
+ Intent sendIntent = createSendImageIntent(
+ Uri.parse("android.resource://com.android.frameworks.coretests/"
+ + R.drawable.test320x240));
+ ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
+ ChooserActivityOverrideData.getInstance().isImageType = true;
+ sendIntent.putExtra(Intent.EXTRA_TEXT, "https://google.com/search?q=google");
+
+ Intent alternativeIntent = createSendTextIntent();
+ final String text = "alternative intent";
+ alternativeIntent.putExtra(Intent.EXTRA_TEXT, text);
+
+ List<ResolvedComponentInfo> resolvedComponentInfos = Arrays.asList(
+ ResolverDataProvider.createResolvedComponentInfo(
+ new ComponentName("org.imageviewer", "ImageTarget"),
+ sendIntent),
+ ResolverDataProvider.createResolvedComponentInfo(
+ new ComponentName("org.textviewer", "UriTarget"),
+ alternativeIntent)
+ );
+
+ when(
+ ChooserActivityOverrideData
+ .getInstance()
+ .resolverListController
+ .getResolversForIntent(
+ Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class)))
+ .thenReturn(resolvedComponentInfos);
+
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
+ waitForIdle();
+
+ onView(withId(R.id.include_text_action))
+ .check(matches(isDisplayed()))
+ .perform(click());
+ waitForIdle();
+
+ AtomicReference<Intent> launchedIntentRef = new AtomicReference<>();
+ ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
+ launchedIntentRef.set(targetInfo.getTargetIntent());
+ return true;
+ };
+
+ onView(withText(resolvedComponentInfos.get(1).getResolveInfoAt(0).activityInfo.name))
+ .perform(click());
+ waitForIdle();
+ assertThat(launchedIntentRef.get().getStringExtra(Intent.EXTRA_TEXT)).isEqualTo(text);
+ }
+
+ @Test
public void copyTextToClipboard() throws Exception {
Intent sendIntent = createSendTextIntent();
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);