summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java178
-rw-r--r--core/java/com/android/internal/util/ImageUtils.java59
-rw-r--r--core/res/res/layout/chooser_grid.xml83
-rw-r--r--core/res/res/values/dimens.xml1
-rw-r--r--core/res/res/values/symbols.xml8
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java91
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java9
7 files changed, 414 insertions, 15 deletions
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index cfe293925058..ee96ae985331 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -16,6 +16,9 @@
package com.android.internal.app;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.prediction.AppPredictionContext;
@@ -27,6 +30,7 @@ import android.app.prediction.AppTargetId;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -46,6 +50,7 @@ import android.database.DataSetObserver;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
@@ -93,11 +98,13 @@ import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.util.ImageUtils;
import com.google.android.collect.Lists;
import java.io.File;
import java.io.IOException;
+import java.lang.annotation.Retention;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -174,6 +181,15 @@ public class ChooserActivity extends ResolverActivity {
private static final int SHORTCUT_MANAGER_SHARE_TARGET_RESULT = 3;
private static final int SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED = 4;
+ @Retention(SOURCE)
+ @IntDef({CONTENT_PREVIEW_FILE, CONTENT_PREVIEW_IMAGE, CONTENT_PREVIEW_TEXT})
+ private @interface ContentPreviewType {
+ }
+
+ private static final int CONTENT_PREVIEW_IMAGE = 0;
+ private static final int CONTENT_PREVIEW_FILE = 1;
+ private static final int CONTENT_PREVIEW_TEXT = 2;
+
private final Handler mChooserHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
@@ -448,18 +464,35 @@ public class ChooserActivity extends ResolverActivity {
return;
}
- ViewGroup contentPreviewLayout = findViewById(R.id.content_preview);
String action = targetIntent.getAction();
if (!(Intent.ACTION_SEND.equals(action) || Intent.ACTION_SEND_MULTIPLE.equals(action))) {
- contentPreviewLayout.setVisibility(View.GONE);
return;
}
- showDefaultContentPreview(contentPreviewLayout, targetIntent);
+ int previewType = findPreferredContentPreview(targetIntent, getContentResolver());
+ displayContentPreview(previewType, targetIntent);
+ }
+
+ private void displayContentPreview(@ContentPreviewType int previewType, Intent targetIntent) {
+ switch (previewType) {
+ case CONTENT_PREVIEW_TEXT:
+ displayTextContentPreview(targetIntent);
+ break;
+ case CONTENT_PREVIEW_IMAGE:
+ displayImageContentPreview(targetIntent);
+ break;
+ case CONTENT_PREVIEW_FILE:
+ displayFileContentPreview(targetIntent);
+ break;
+ default:
+ Log.e(TAG, "Unexpected content preview type: " + previewType);
+ }
}
- private void showDefaultContentPreview(final ViewGroup parentLayout,
- final Intent targetIntent) {
+ private void displayTextContentPreview(Intent targetIntent) {
+ ViewGroup contentPreviewLayout = findViewById(R.id.content_preview_text_area);
+ contentPreviewLayout.setVisibility(View.VISIBLE);
+
CharSequence sharingText = targetIntent.getCharSequenceExtra(Intent.EXTRA_TEXT);
if (sharingText == null) {
findViewById(R.id.content_preview_text_layout).setVisibility(View.GONE);
@@ -498,6 +531,105 @@ public class ChooserActivity extends ResolverActivity {
}
}
+ private void displayImageContentPreview(Intent targetIntent) {
+ ViewGroup contentPreviewLayout = findViewById(R.id.content_preview_image_area);
+ contentPreviewLayout.setVisibility(View.VISIBLE);
+
+ String action = targetIntent.getAction();
+ if (Intent.ACTION_SEND.equals(action)) {
+ Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM);
+ loadUriIntoView(R.id.content_preview_image_1_large, uri);
+ } else {
+ ContentResolver resolver = getContentResolver();
+
+ List<Uri> uris = targetIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
+ List<Uri> imageUris = new ArrayList<>();
+ for (Uri uri : uris) {
+ if (isImageType(resolver.getType(uri))) {
+ imageUris.add(uri);
+ }
+ }
+
+ if (imageUris.size() == 0) {
+ Log.i(TAG, "Attempted to display image preview area with zero"
+ + " available images detected in EXTRA_STREAM list");
+ return;
+ }
+
+ loadUriIntoView(R.id.content_preview_image_1_large, imageUris.get(0));
+
+ if (imageUris.size() == 2) {
+ loadUriIntoView(R.id.content_preview_image_2_large, imageUris.get(1));
+ } else if (imageUris.size() > 2) {
+ loadUriIntoView(R.id.content_preview_image_2_small, imageUris.get(1));
+ RoundedRectImageView imageView = loadUriIntoView(
+ R.id.content_preview_image_3_small, imageUris.get(2));
+
+ if (imageUris.size() > 3) {
+ imageView.setExtraImageCount(imageUris.size() - 3);
+ }
+ }
+ }
+ }
+
+ private void displayFileContentPreview(Intent targetIntent) {
+ // support coming
+ }
+
+ private RoundedRectImageView loadUriIntoView(int imageResourceId, Uri uri) {
+ RoundedRectImageView imageView = findViewById(imageResourceId);
+ imageView.setVisibility(View.VISIBLE);
+ Bitmap bmp = loadThumbnail(uri, new Size(200, 200));
+ imageView.setImageBitmap(bmp);
+
+ return imageView;
+ }
+
+ @VisibleForTesting
+ protected boolean isImageType(String mimeType) {
+ return mimeType != null && mimeType.startsWith("image/");
+ }
+
+ @ContentPreviewType
+ private int findPreferredContentPreview(Uri uri, ContentResolver resolver) {
+ if (uri == null) {
+ return CONTENT_PREVIEW_TEXT;
+ }
+
+ String mimeType = resolver.getType(uri);
+ return isImageType(mimeType) ? CONTENT_PREVIEW_IMAGE : CONTENT_PREVIEW_FILE;
+ }
+
+ /**
+ * In {@link android.content.Intent#getType}, the app may specify a very general
+ * mime-type that broadly covers all data being shared, such as {@literal *}/*
+ * when sending an image and text. We therefore should inspect each item for the
+ * the preferred type, in order of IMAGE, FILE, TEXT.
+ */
+ @ContentPreviewType
+ private int findPreferredContentPreview(Intent targetIntent, ContentResolver resolver) {
+ String action = targetIntent.getAction();
+ if (Intent.ACTION_SEND.equals(action)) {
+ Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM);
+ return findPreferredContentPreview(uri, resolver);
+ } else if (Intent.ACTION_SEND_MULTIPLE.equals(action)) {
+ List<Uri> uris = targetIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
+ if (uris == null || uris.isEmpty()) {
+ return CONTENT_PREVIEW_TEXT;
+ }
+
+ for (Uri uri : uris) {
+ if (findPreferredContentPreview(uri, resolver) == CONTENT_PREVIEW_IMAGE) {
+ return CONTENT_PREVIEW_IMAGE;
+ }
+ }
+
+ return CONTENT_PREVIEW_FILE;
+ }
+
+ return CONTENT_PREVIEW_TEXT;
+ }
+
static SharedPreferences getPinnedSharedPrefs(Context context) {
// The code below is because in the android:ui process, no one can hear you scream.
// The package info in the context isn't initialized in the way it is for normal apps,
@@ -1114,7 +1246,8 @@ public class ChooserActivity extends ResolverActivity {
}
try {
- return getContentResolver().loadThumbnail(uri, size, null);
+ return ImageUtils.decodeSampledBitmapFromStream(getContentResolver(),
+ uri, size.getWidth(), size.getHeight());
} catch (IOException | NullPointerException ex) {
Log.w(TAG, "Error loading preview thumbnail for uri: " + uri.toString(), ex);
}
@@ -2045,6 +2178,9 @@ public class ChooserActivity extends ResolverActivity {
public static class RoundedRectImageView extends ImageView {
private int mRadius = 0;
private Path mPath = new Path();
+ private Paint mOverlayPaint = new Paint(0);
+ private Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ private String mExtraImageCount = null;
public RoundedRectImageView(Context context) {
super(context);
@@ -2062,6 +2198,14 @@ public class ChooserActivity extends ResolverActivity {
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
mRadius = context.getResources().getDimensionPixelSize(R.dimen.chooser_corner_radius);
+
+ mOverlayPaint.setColor(0x99000000);
+ mOverlayPaint.setStyle(Paint.Style.FILL);
+
+ mTextPaint.setColor(Color.WHITE);
+ mTextPaint.setTextSize(context.getResources()
+ .getDimensionPixelSize(R.dimen.chooser_preview_image_font_size));
+ mTextPaint.setTextAlign(Paint.Align.CENTER);
}
private void updatePath(int width, int height) {
@@ -2083,12 +2227,24 @@ public class ChooserActivity extends ResolverActivity {
updatePath(getWidth(), getHeight());
}
+ /**
+ * Display an overlay with extra image count on 3rd image
+ */
+ public void setExtraImageCount(int count) {
+ if (count > 0) {
+ this.mExtraImageCount = "+" + count;
+ } else {
+ this.mExtraImageCount = null;
+ }
+ }
+
@Override
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
super.onSizeChanged(width, height, oldWidth, oldHeight);
updatePath(width, height);
}
+
@Override
protected void onDraw(Canvas canvas) {
if (mRadius != 0) {
@@ -2096,6 +2252,16 @@ public class ChooserActivity extends ResolverActivity {
}
super.onDraw(canvas);
+
+ if (mExtraImageCount != null) {
+ canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), mOverlayPaint);
+
+ int xPos = canvas.getWidth() / 2;
+ int yPos = (int) ((canvas.getHeight() / 2.0f)
+ - ((mTextPaint.descent() + mTextPaint.ascent()) / 2.0f));
+
+ canvas.drawText(mExtraImageCount, xPos, yPos, mTextPaint);
+ }
}
}
}
diff --git a/core/java/com/android/internal/util/ImageUtils.java b/core/java/com/android/internal/util/ImageUtils.java
index 7d56e9e53b1c..195ae52ce977 100644
--- a/core/java/com/android/internal/util/ImageUtils.java
+++ b/core/java/com/android/internal/util/ImageUtils.java
@@ -16,14 +16,20 @@
package com.android.internal.util;
+import android.content.ContentResolver;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
+import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.net.Uri;
+
+import java.io.IOException;
+import java.io.InputStream;
/**
* Utility class for image analysis and processing.
@@ -80,7 +86,7 @@ public class ImageUtils {
width = height = COMPACT_BITMAP_SIZE;
}
- final int size = height*width;
+ final int size = height * width;
ensureBufferSize(size);
bitmap.getPixels(mTempBuffer, 0, width, 0, 0, width, height);
for (int i = 0; i < size; i++) {
@@ -156,4 +162,55 @@ public class ImageUtils {
return result;
}
+
+ /**
+ * @see https://developer.android.com/topic/performance/graphics/load-bitmap
+ */
+ public static int calculateInSampleSize(BitmapFactory.Options options,
+ int reqWidth, int reqHeight) {
+ // Raw height and width of image
+ final int height = options.outHeight;
+ final int width = options.outWidth;
+ int inSampleSize = 1;
+
+ if (height > reqHeight || width > reqWidth) {
+ final int halfHeight = height / 2;
+ final int halfWidth = width / 2;
+
+ // Calculate the largest inSampleSize value that is a power of 2 and keeps both
+ // height and width larger than the requested height and width.
+ while ((halfHeight / inSampleSize) >= reqHeight
+ && (halfWidth / inSampleSize) >= reqWidth) {
+ inSampleSize *= 2;
+ }
+ }
+
+ return inSampleSize;
+ }
+
+ /**
+ * Load a bitmap, and attempt to downscale to the required size, to save
+ * on memory.
+ *
+ * @see https://developer.android.com/topic/performance/graphics/load-bitmap
+ */
+ public static Bitmap decodeSampledBitmapFromStream(ContentResolver resolver,
+ Uri uri, int reqWidth, int reqHeight) throws IOException {
+
+ final BitmapFactory.Options options = new BitmapFactory.Options();
+ try (InputStream is = resolver.openInputStream(uri)) {
+ // First decode with inJustDecodeBounds=true to check dimensions
+ options.inJustDecodeBounds = true;
+ BitmapFactory.decodeStream(is, null, options);
+
+ options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
+ }
+
+ // need to do this twice as the InputStream is consumed in the first call,
+ // and not all InputStreams support marks
+ try (InputStream is = resolver.openInputStream(uri)) {
+ options.inJustDecodeBounds = false;
+ return BitmapFactory.decodeStream(is, null, options);
+ }
+ }
}
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
index a24f920de732..f78466168e13 100644
--- a/core/res/res/layout/chooser_grid.xml
+++ b/core/res/res/layout/chooser_grid.xml
@@ -59,12 +59,84 @@
android:layout_centerHorizontal="true"/>
</RelativeLayout>
+ <!-- The following 3 layouts are mutually exclusive. One of them will be
+ set VISIBLE programatically, when the optimal preview type can be
+ determined by inspecting the data being shared. This path was chosen
+ b/c inflating layouts in code had sizing problems with this widget. -->
+
+ <!-- Layout Option 1: Supporting up to 3 images for preview -->
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:background="?attr/colorBackgroundFloating">
+ <RelativeLayout
+ android:id="@+id/content_preview_image_area"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:paddingBottom="@dimen/chooser_view_spacing"
+ android:visibility="gone"
+ android:background="?attr/colorBackgroundFloating">
+
+ <view class="com.android.internal.app.ChooserActivity$RoundedRectImageView"
+ android:id="@+id/content_preview_image_1_large"
+ android:visibility="gone"
+ android:layout_width="120dp"
+ android:layout_height="140dp"
+ android:layout_alignParentTop="true"
+ android:adjustViewBounds="true"
+ android:gravity="center"
+ android:scaleType="centerCrop"/>
+
+ <view class="com.android.internal.app.ChooserActivity$RoundedRectImageView"
+ android:id="@+id/content_preview_image_2_large"
+ android:visibility="gone"
+ android:layout_width="120dp"
+ android:layout_height="140dp"
+ android:layout_alignParentTop="true"
+ android:layout_toRightOf="@id/content_preview_image_1_large"
+ android:layout_marginLeft="10dp"
+ android:adjustViewBounds="true"
+ android:gravity="center"
+ android:scaleType="centerCrop"/>
+
+ <view class="com.android.internal.app.ChooserActivity$RoundedRectImageView"
+ android:id="@+id/content_preview_image_2_small"
+ android:visibility="gone"
+ android:layout_width="120dp"
+ android:layout_height="65dp"
+ android:layout_alignParentTop="true"
+ android:layout_toRightOf="@id/content_preview_image_1_large"
+ android:layout_marginLeft="10dp"
+ android:adjustViewBounds="true"
+ android:gravity="center"
+ android:scaleType="centerCrop"/>
+
+ <view class="com.android.internal.app.ChooserActivity$RoundedRectImageView"
+ android:id="@+id/content_preview_image_3_small"
+ android:visibility="gone"
+ android:layout_width="120dp"
+ android:layout_height="65dp"
+ android:layout_below="@id/content_preview_image_2_small"
+ android:layout_toRightOf="@id/content_preview_image_1_large"
+ android:layout_marginLeft="10dp"
+ android:layout_marginTop="10dp"
+ android:adjustViewBounds="true"
+ android:gravity="center"
+ android:scaleType="centerCrop"/>
+
+ </RelativeLayout>
+ </LinearLayout>
+
+ <!-- Layout Option 2: Text preview, with optional title and thumbnail -->
<LinearLayout
- android:id="@+id/content_preview"
+ android:id="@+id/content_preview_text_area"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="@dimen/chooser_view_spacing"
+ android:visibility="gone"
android:background="?attr/colorBackgroundFloating">
<LinearLayout
@@ -108,15 +180,12 @@
<view class="com.android.internal.app.ChooserActivity$RoundedRectImageView"
android:id="@+id/content_preview_thumbnail"
- android:layout_width="80dp"
- android:layout_height="80dp"
- android:layout_marginRight="12dp"
+ android:layout_width="75dp"
+ android:layout_height="75dp"
+ android:layout_marginRight="16dp"
android:adjustViewBounds="true"
android:layout_gravity="center_vertical"
android:gravity="center"
- android:maxWidth="70dp"
- android:maxHeight="70dp"
- android:padding="5dp"
android:scaleType="centerCrop"/>
<TextView
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 38367fbf3f31..9f86f8416fb9 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -720,4 +720,5 @@
<dimen name="chooser_view_spacing">18dp</dimen>
<dimen name="chooser_edge_margin_thin">16dp</dimen>
<dimen name="chooser_edge_margin_normal">24dp</dimen>
+ <dimen name="chooser_preview_image_font_size">20sp</dimen>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a06222c3437f..322c1b6131f2 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -50,9 +50,14 @@
<java-symbol type="id" name="characterPicker" />
<java-symbol type="id" name="clearDefaultHint" />
<java-symbol type="id" name="contentPanel" />
- <java-symbol type="id" name="content_preview" />
+ <java-symbol type="id" name="content_preview_image_area" />
+ <java-symbol type="id" name="content_preview_image_1_large" />
+ <java-symbol type="id" name="content_preview_image_2_large" />
+ <java-symbol type="id" name="content_preview_image_2_small" />
+ <java-symbol type="id" name="content_preview_image_3_small" />
<java-symbol type="id" name="content_preview_thumbnail" />
<java-symbol type="id" name="content_preview_text" />
+ <java-symbol type="id" name="content_preview_text_area" />
<java-symbol type="id" name="content_preview_text_layout" />
<java-symbol type="id" name="content_preview_title" />
<java-symbol type="id" name="content_preview_title_layout" />
@@ -2724,6 +2729,7 @@
<java-symbol type="dimen" name="chooser_view_spacing" />
<java-symbol type="dimen" name="chooser_edge_margin_thin" />
<java-symbol type="dimen" name="chooser_edge_margin_normal" />
+ <java-symbol type="dimen" name="chooser_preview_image_font_size"/>
<java-symbol type="layout" name="chooser_grid" />
<java-symbol type="layout" name="resolve_grid_item" />
<java-symbol type="id" name="day_picker_view_pager" />
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index 6b9e69cdb853..b6f56ada445e 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -421,6 +421,83 @@ public class ChooserActivityTest {
assertThat("text/plain", is(clipDescription.getMimeType(0)));
}
+ @Test
+ public void oneVisibleImagePreview() throws InterruptedException {
+ Uri uri = Uri.parse("android.resource://com.android.frameworks.coretests/"
+ + com.android.frameworks.coretests.R.drawable.test320x240);
+
+ ArrayList<Uri> uris = new ArrayList<>();
+ uris.add(uri);
+
+ Intent sendIntent = createSendImageIntentWithPreview(uris);
+ sOverrides.previewThumbnail = createBitmap();
+
+ List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
+
+ when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
+ waitForIdle();
+ onView(withId(R.id.content_preview_image_1_large)).check(matches(isDisplayed()));
+ onView(withId(R.id.content_preview_image_2_large)).check(matches(not(isDisplayed())));
+ onView(withId(R.id.content_preview_image_2_small)).check(matches(not(isDisplayed())));
+ onView(withId(R.id.content_preview_image_3_small)).check(matches(not(isDisplayed())));
+ }
+
+ @Test
+ public void twoVisibleImagePreview() throws InterruptedException {
+ Uri uri = Uri.parse("android.resource://com.android.frameworks.coretests/"
+ + com.android.frameworks.coretests.R.drawable.test320x240);
+
+ ArrayList<Uri> uris = new ArrayList<>();
+ uris.add(uri);
+ uris.add(uri);
+
+ Intent sendIntent = createSendImageIntentWithPreview(uris);
+ sOverrides.previewThumbnail = createBitmap();
+
+ List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
+
+ when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
+ waitForIdle();
+ onView(withId(R.id.content_preview_image_1_large)).check(matches(isDisplayed()));
+ onView(withId(R.id.content_preview_image_2_large)).check(matches(isDisplayed()));
+ onView(withId(R.id.content_preview_image_2_small)).check(matches(not(isDisplayed())));
+ onView(withId(R.id.content_preview_image_3_small)).check(matches(not(isDisplayed())));
+ }
+
+ @Test
+ public void threeOrMoreVisibleImagePreview() throws InterruptedException {
+ Uri uri = Uri.parse("android.resource://com.android.frameworks.coretests/"
+ + com.android.frameworks.coretests.R.drawable.test320x240);
+
+ ArrayList<Uri> uris = new ArrayList<>();
+ uris.add(uri);
+ uris.add(uri);
+ uris.add(uri);
+ uris.add(uri);
+ uris.add(uri);
+
+ Intent sendIntent = createSendImageIntentWithPreview(uris);
+ sOverrides.previewThumbnail = createBitmap();
+
+ List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
+
+ when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
+ waitForIdle();
+ onView(withId(R.id.content_preview_image_1_large)).check(matches(isDisplayed()));
+ onView(withId(R.id.content_preview_image_2_large)).check(matches(not(isDisplayed())));
+ onView(withId(R.id.content_preview_image_2_small)).check(matches(isDisplayed()));
+ onView(withId(R.id.content_preview_image_3_small)).check(matches(isDisplayed()));
+ }
+
private Intent createSendTextIntent() {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
@@ -441,6 +518,20 @@ public class ChooserActivityTest {
return sendIntent;
}
+ private Intent createSendImageIntentWithPreview(ArrayList<Uri> uris) {
+ Intent sendIntent = new Intent();
+
+ if (uris.size() > 1) {
+ sendIntent.setAction(Intent.ACTION_SEND_MULTIPLE);
+ sendIntent.putExtra(Intent.EXTRA_STREAM, uris);
+ } else {
+ sendIntent.setAction(Intent.ACTION_SEND);
+ sendIntent.putExtra(Intent.EXTRA_STREAM, uris.get(0));
+ }
+
+ return sendIntent;
+ }
+
private Intent createViewTextIntent() {
Intent viewIntent = new Intent();
viewIntent.setAction(Intent.ACTION_VIEW);
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
index 637d2eafc7af..ec8122fb2e47 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
@@ -85,6 +85,15 @@ public class ChooserWrapperActivity extends ChooserActivity {
return super.loadThumbnail(uri, size);
}
+ @Override
+ protected boolean isImageType(String mimeType) {
+ if (sOverrides.previewThumbnail != null) {
+ return true;
+ }
+
+ return super.isImageType(mimeType);
+ }
+
/**
* We cannot directly mock the activity created since instrumentation creates it.
* <p>