summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
Diffstat (limited to 'java')
-rw-r--r--java/res/drawable/edit_action_background.xml29
-rw-r--r--java/res/layout-h480dp/image_preview_image_item.xml22
-rw-r--r--java/res/layout/chooser_grid_preview_text.xml54
-rw-r--r--java/src/com/android/intentresolver/ChooserActionFactory.java58
-rw-r--r--java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java13
-rw-r--r--java/src/com/android/intentresolver/contentpreview/ContentPreviewUi.java16
-rw-r--r--java/src/com/android/intentresolver/contentpreview/FileContentPreviewUi.java4
-rw-r--r--java/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUi.java17
-rw-r--r--java/src/com/android/intentresolver/contentpreview/TextContentPreviewUi.java22
-rw-r--r--java/src/com/android/intentresolver/contentpreview/UnifiedContentPreviewUi.java20
-rw-r--r--java/src/com/android/intentresolver/widget/ScrollableImagePreviewView.kt17
-rw-r--r--java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java8
-rw-r--r--java/tests/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUiTest.kt18
-rw-r--r--java/tests/src/com/android/intentresolver/contentpreview/ContentPreviewUiTest.kt44
-rw-r--r--java/tests/src/com/android/intentresolver/widget/BatchPreviewLoaderTest.kt148
15 files changed, 221 insertions, 269 deletions
diff --git a/java/res/drawable/edit_action_background.xml b/java/res/drawable/edit_action_background.xml
new file mode 100644
index 00000000..91726f49
--- /dev/null
+++ b/java/res/drawable/edit_action_background.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:color="?android:attr/colorControlHighlight"
+ >
+ <item>
+ <inset android:inset="8dp">
+ <shape android:shape="rectangle">
+ <corners android:radius="12dp" />
+ <solid android:color="?androidprv:attr/materialColorSecondaryFixed"/>
+ </shape>
+ </inset>
+ </item>
+</ripple>
diff --git a/java/res/layout-h480dp/image_preview_image_item.xml b/java/res/layout-h480dp/image_preview_image_item.xml
index db44c8be..ac63b2d5 100644
--- a/java/res/layout-h480dp/image_preview_image_item.xml
+++ b/java/res/layout-h480dp/image_preview_image_item.xml
@@ -17,6 +17,7 @@
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:layout_width="wrap_content"
android:layout_height="@dimen/chooser_preview_image_height_tall">
@@ -52,4 +53,25 @@
android:tint="@android:color/white"
android:layout_gravity="top|end" />
</FrameLayout>
+
+ <FrameLayout
+ android:id="@+id/edit"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ android:background="@drawable/edit_action_background"
+ android:drawableTint="?androidprv:attr/materialColorSecondaryFixed"
+ android:contentDescription="@string/screenshot_edit"
+ android:visibility="gone"
+ >
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:padding="4dp"
+ android:tint="?androidprv:attr/materialColorOnSecondaryFixed"
+ android:src="@androidprv:drawable/ic_screenshot_edit"
+ />
+ </FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/java/res/layout/chooser_grid_preview_text.xml b/java/res/layout/chooser_grid_preview_text.xml
index 44163b49..96496a30 100644
--- a/java/res/layout/chooser_grid_preview_text.xml
+++ b/java/res/layout/chooser_grid_preview_text.xml
@@ -29,7 +29,7 @@
<include layout="@layout/chooser_headline_row" />
- <RelativeLayout
+ <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
@@ -44,9 +44,9 @@
android:id="@androidprv:id/content_preview_thumbnail"
android:layout_width="@dimen/width_text_image_preview_size"
android:layout_height="@dimen/width_text_image_preview_size"
- android:layout_alignParentStart="true"
- android:layout_centerVertical="true"
- android:layout_marginEnd="@dimen/chooser_edge_margin_normal_half"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
android:adjustViewBounds="true"
android:gravity="center"
app:radius="@dimen/chooser_corner_radius_small"
@@ -54,11 +54,15 @@
<TextView
android:id="@androidprv:id/content_preview_title"
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_toEndOf="@androidprv:id/content_preview_thumbnail"
- android:layout_alignParentTop="true"
- android:layout_alignWithParentIfMissing="true"
+ app:layout_constraintStart_toEndOf="@androidprv:id/content_preview_thumbnail"
+ app:layout_constraintEnd_toStartOf="@id/copy"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toTopOf="@androidprv:id/content_preview_text"
+ android:layout_marginStart="@dimen/chooser_edge_margin_normal_half"
+ app:layout_goneMarginStart="0dp"
+ app:layout_constraintVertical_chainStyle="packed"
android:ellipsize="end"
android:maxLines="1"
android:textAlignment="gravity"
@@ -69,11 +73,14 @@
<TextView
android:id="@androidprv:id/content_preview_text"
- android:layout_width="match_parent"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_toEndOf="@androidprv:id/content_preview_thumbnail"
- android:layout_below="@androidprv:id/content_preview_title"
- android:layout_alignWithParentIfMissing="true"
+ app:layout_constraintStart_toEndOf="@androidprv:id/content_preview_thumbnail"
+ app:layout_constraintEnd_toStartOf="@id/copy"
+ app:layout_constraintTop_toBottomOf="@androidprv:id/content_preview_title"
+ app:layout_constraintBottom_toBottomOf="parent"
+ android:layout_marginStart="@dimen/chooser_edge_margin_normal_half"
+ app:layout_goneMarginStart="0dp"
android:ellipsize="end"
android:fontFamily="@androidprv:string/config_headlineFontFamily"
android:textColor="?androidprv:attr/materialColorOnSurfaceVariant"
@@ -81,7 +88,28 @@
android:textDirection="locale"
android:maxLines="@integer/text_preview_lines"
android:focusable="true"/>
- </RelativeLayout>
+
+ <FrameLayout
+ android:id="@+id/copy"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:layout_constraintStart_toEndOf="@androidprv:id/content_preview_text"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="1"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ android:layout_margin="8dp"
+ android:padding="8dp"
+ android:contentDescription="@android:string/copy"
+ >
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:tint="?androidprv:attr/materialColorOnSurfaceVariant"
+ android:src="@androidprv:drawable/ic_menu_copy_material"
+ />
+ </FrameLayout>
+ </androidx.constraintlayout.widget.ConstraintLayout>
<include layout="@layout/chooser_action_row" />
diff --git a/java/src/com/android/intentresolver/ChooserActionFactory.java b/java/src/com/android/intentresolver/ChooserActionFactory.java
index f355d9d4..6ec62753 100644
--- a/java/src/com/android/intentresolver/ChooserActionFactory.java
+++ b/java/src/com/android/intentresolver/ChooserActionFactory.java
@@ -84,11 +84,8 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio
private static final String IMAGE_EDITOR_SHARED_ELEMENT = "screenshot_preview_image";
private final Context mContext;
- private final String mCopyButtonLabel;
- private final Drawable mCopyButtonDrawable;
- private final Runnable mOnCopyButtonClicked;
- private final TargetInfo mEditSharingTarget;
- private final Runnable mOnEditButtonClicked;
+ private final Runnable mCopyButtonRunnable;
+ private final Runnable mEditButtonRunnable;
private final ImmutableList<ChooserAction> mCustomActions;
private final @Nullable ChooserAction mModifyShareAction;
private final Consumer<Boolean> mExcludeSharedTextAction;
@@ -119,19 +116,13 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio
Consumer</* @Nullable */ Integer> finishCallback) {
this(
context,
- context.getString(com.android.internal.R.string.copy),
- context.getDrawable(com.android.internal.R.drawable.ic_menu_copy_material),
- makeOnCopyRunnable(
+ makeCopyButtonRunnable(
context,
chooserRequest.getTargetIntent(),
chooserRequest.getReferrerPackageName(),
finishCallback,
logger),
- getEditSharingTarget(
- context,
- chooserRequest.getTargetIntent(),
- integratedDeviceComponents),
- makeOnEditRunnable(
+ makeEditButtonRunnable(
getEditSharingTarget(
context,
chooserRequest.getTargetIntent(),
@@ -149,22 +140,16 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio
@VisibleForTesting
ChooserActionFactory(
Context context,
- String copyButtonLabel,
- Drawable copyButtonDrawable,
- Runnable onCopyButtonClicked,
- TargetInfo editSharingTarget,
- Runnable onEditButtonClicked,
+ Runnable copyButtonRunnable,
+ Runnable editButtonRunnable,
List<ChooserAction> customActions,
@Nullable ChooserAction modifyShareAction,
Consumer<Boolean> onUpdateSharedTextIsExcluded,
ChooserActivityLogger logger,
Consumer</* @Nullable */ Integer> finishCallback) {
mContext = context;
- mCopyButtonLabel = copyButtonLabel;
- mCopyButtonDrawable = copyButtonDrawable;
- mOnCopyButtonClicked = onCopyButtonClicked;
- mEditSharingTarget = editSharingTarget;
- mOnEditButtonClicked = onEditButtonClicked;
+ mCopyButtonRunnable = copyButtonRunnable;
+ mEditButtonRunnable = editButtonRunnable;
mCustomActions = ImmutableList.copyOf(customActions);
mModifyShareAction = modifyShareAction;
mExcludeSharedTextAction = onUpdateSharedTextIsExcluded;
@@ -172,29 +157,16 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio
mFinishCallback = finishCallback;
}
- /** Create an action that copies the share content to the clipboard. */
@Override
- public ActionRow.Action createCopyButton() {
- return new ActionRow.Action(
- com.android.internal.R.id.chooser_copy_button,
- mCopyButtonLabel,
- mCopyButtonDrawable,
- mOnCopyButtonClicked);
+ @Nullable
+ public Runnable getEditButtonRunnable() {
+ return mEditButtonRunnable;
}
- /** Create an action that opens the share content in a system-default editor. */
@Override
@Nullable
- public ActionRow.Action createEditButton() {
- if (mEditSharingTarget == null) {
- return null;
- }
-
- return new ActionRow.Action(
- com.android.internal.R.id.chooser_edit_button,
- mEditSharingTarget.getDisplayLabel(),
- mEditSharingTarget.getDisplayIconHolder().getDisplayIcon(),
- mOnEditButtonClicked);
+ public Runnable getCopyButtonRunnable() {
+ return mCopyButtonRunnable;
}
/** Create custom actions */
@@ -247,7 +219,7 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio
return mExcludeSharedTextAction;
}
- private static Runnable makeOnCopyRunnable(
+ private static Runnable makeCopyButtonRunnable(
Context context,
Intent targetIntent,
String referrerPackageName,
@@ -344,7 +316,7 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio
return dri;
}
- private static Runnable makeOnEditRunnable(
+ private static Runnable makeEditButtonRunnable(
TargetInfo editSharingTarget,
Callable</* @Nullable */ View> firstVisibleImageQuery,
ActionActivityStarter activityStarter,
diff --git a/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java
index 9100b392..e8367c4e 100644
--- a/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java
+++ b/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java
@@ -53,12 +53,17 @@ public final class ChooserContentPreviewUi {
* TODO: clarify why action buttons are part of preview logic.
*/
public interface ActionFactory {
- /** Create an action that copies the share content to the clipboard. */
- ActionRow.Action createCopyButton();
+ /**
+ * @return Runnable to be run when an edit button is clicked (if available).
+ */
+ @Nullable
+ Runnable getEditButtonRunnable();
- /** Create an action that opens the share content in a system-default editor. */
+ /**
+ * @return Runnable to be run when a copy button is clicked (if available).
+ */
@Nullable
- ActionRow.Action createEditButton();
+ Runnable getCopyButtonRunnable();
/** Create custom actions */
List<ActionRow.Action> createCustomActions();
diff --git a/java/src/com/android/intentresolver/contentpreview/ContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/ContentPreviewUi.java
index 9699594e..07071236 100644
--- a/java/src/com/android/intentresolver/contentpreview/ContentPreviewUi.java
+++ b/java/src/com/android/intentresolver/contentpreview/ContentPreviewUi.java
@@ -32,9 +32,6 @@ import com.android.intentresolver.R;
import com.android.intentresolver.widget.ActionRow;
import com.android.intentresolver.widget.ScrollableImagePreviewView;
-import java.util.ArrayList;
-import java.util.List;
-
abstract class ContentPreviewUi {
private static final int IMAGE_FADE_IN_MILLIS = 150;
static final String TAG = "ChooserPreview";
@@ -45,19 +42,6 @@ abstract class ContentPreviewUi {
public abstract ViewGroup display(
Resources resources, LayoutInflater layoutInflater, ViewGroup parent);
- protected static List<ActionRow.Action> createActions(
- List<ActionRow.Action> systemActions,
- List<ActionRow.Action> customActions) {
- ArrayList<ActionRow.Action> actions =
- new ArrayList<>(systemActions.size() + customActions.size());
- if (customActions.isEmpty()) {
- actions.addAll(systemActions);
- } else {
- actions.addAll(customActions);
- }
- return actions;
- }
-
protected static void updateViewWithImage(ImageView imageView, Bitmap image) {
if (image == null) {
imageView.setVisibility(View.GONE);
diff --git a/java/src/com/android/intentresolver/contentpreview/FileContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/FileContentPreviewUi.java
index 16ff6c23..8d3e62aa 100644
--- a/java/src/com/android/intentresolver/contentpreview/FileContentPreviewUi.java
+++ b/java/src/com/android/intentresolver/contentpreview/FileContentPreviewUi.java
@@ -30,7 +30,6 @@ import androidx.annotation.Nullable;
import com.android.intentresolver.R;
import com.android.intentresolver.widget.ActionRow;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -108,8 +107,7 @@ class FileContentPreviewUi extends ContentPreviewUi {
final ActionRow actionRow =
mContentPreview.findViewById(com.android.internal.R.id.chooser_action_row);
- List<ActionRow.Action> actions =
- createActions(new ArrayList<>(), mActionFactory.createCustomActions());
+ List<ActionRow.Action> actions = mActionFactory.createCustomActions();
actionRow.setActions(actions);
if (actions.isEmpty()) {
mContentPreview.findViewById(R.id.actions_top_divider).setVisibility(View.GONE);
diff --git a/java/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUi.java
index e4e33839..61ca44e0 100644
--- a/java/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUi.java
+++ b/java/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUi.java
@@ -37,7 +37,6 @@ import com.android.intentresolver.R;
import com.android.intentresolver.widget.ActionRow;
import com.android.intentresolver.widget.ScrollableImagePreviewView;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.function.Consumer;
@@ -123,9 +122,7 @@ class FilesPlusTextContentPreviewUi extends ContentPreviewUi {
final ActionRow actionRow =
mContentPreviewView.findViewById(com.android.internal.R.id.chooser_action_row);
- List<ActionRow.Action> actions = createActions(
- createImagePreviewActions(),
- mActionFactory.createCustomActions());
+ List<ActionRow.Action> actions = mActionFactory.createCustomActions();
actionRow.setActions(actions);
if (actions.isEmpty()) {
@@ -141,18 +138,6 @@ class FilesPlusTextContentPreviewUi extends ContentPreviewUi {
return mContentPreviewView;
}
- private List<ActionRow.Action> createImagePreviewActions() {
- ArrayList<ActionRow.Action> actions = new ArrayList<>(2);
- //TODO: add copy action;
- if (mIsSingleImage) {
- ActionRow.Action action = mActionFactory.createEditButton();
- if (action != null) {
- actions.add(action);
- }
- }
- return actions;
- }
-
private void updateUiWithMetadata(ViewGroup contentPreviewView) {
prepareTextPreview(contentPreviewView, mActionFactory);
updateHeadline(contentPreviewView);
diff --git a/java/src/com/android/intentresolver/contentpreview/TextContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/TextContentPreviewUi.java
index 19fd3bb4..c38ed03a 100644
--- a/java/src/com/android/intentresolver/contentpreview/TextContentPreviewUi.java
+++ b/java/src/com/android/intentresolver/contentpreview/TextContentPreviewUi.java
@@ -33,9 +33,6 @@ import androidx.lifecycle.Lifecycle;
import com.android.intentresolver.R;
import com.android.intentresolver.widget.ActionRow;
-import java.util.ArrayList;
-import java.util.List;
-
class TextContentPreviewUi extends ContentPreviewUi {
private final Lifecycle mLifecycle;
@Nullable
@@ -85,10 +82,7 @@ class TextContentPreviewUi extends ContentPreviewUi {
final ActionRow actionRow =
contentPreviewLayout.findViewById(com.android.internal.R.id.chooser_action_row);
- actionRow.setActions(
- createActions(
- createTextPreviewActions(),
- mActionFactory.createCustomActions()));
+ actionRow.setActions(mActionFactory.createCustomActions());
if (mSharingText == null) {
contentPreviewLayout
@@ -129,14 +123,16 @@ class TextContentPreviewUi extends ContentPreviewUi {
bitmap));
}
+ Runnable onCopy = mActionFactory.getCopyButtonRunnable();
+ View copyButton = contentPreviewLayout.findViewById(R.id.copy);
+ if (onCopy != null) {
+ copyButton.setOnClickListener((v) -> onCopy.run());
+ } else {
+ copyButton.setVisibility(View.GONE);
+ }
+
displayHeadline(contentPreviewLayout, mHeadlineGenerator.getTextHeadline(mSharingText));
return contentPreviewLayout;
}
-
- private List<ActionRow.Action> createTextPreviewActions() {
- ArrayList<ActionRow.Action> actions = new ArrayList<>(2);
- actions.add(mActionFactory.createCopyButton());
- return actions;
- }
}
diff --git a/java/src/com/android/intentresolver/contentpreview/UnifiedContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/UnifiedContentPreviewUi.java
index 26f4d007..eb3e8e72 100644
--- a/java/src/com/android/intentresolver/contentpreview/UnifiedContentPreviewUi.java
+++ b/java/src/com/android/intentresolver/contentpreview/UnifiedContentPreviewUi.java
@@ -91,9 +91,7 @@ class UnifiedContentPreviewUi extends ContentPreviewUi {
final ActionRow actionRow =
mContentPreviewView.findViewById(com.android.internal.R.id.chooser_action_row);
- List<ActionRow.Action> actions = createActions(
- createImagePreviewActions(),
- mActionFactory.createCustomActions());
+ List<ActionRow.Action> actions = mActionFactory.createCustomActions();
actionRow.setActions(actions);
if (actions.isEmpty()) {
mContentPreviewView.findViewById(R.id.actions_top_divider).setVisibility(View.GONE);
@@ -135,9 +133,11 @@ class UnifiedContentPreviewUi extends ContentPreviewUi {
allVideos = allVideos && previewType == ScrollableImagePreviewView.PreviewType.Video;
if (fileInfo.getPreviewUri() != null) {
+ Runnable editAction =
+ mShowEditAction ? mActionFactory.getEditButtonRunnable() : null;
previews.add(
new ScrollableImagePreviewView.Preview(
- previewType, fileInfo.getPreviewUri()));
+ previewType, fileInfo.getPreviewUri(), editAction));
}
}
@@ -151,16 +151,4 @@ class UnifiedContentPreviewUi extends ContentPreviewUi {
displayHeadline(contentPreviewView, mHeadlineGenerator.getFilesHeadline(count));
}
}
-
- private List<ActionRow.Action> createImagePreviewActions() {
- ArrayList<ActionRow.Action> actions = new ArrayList<>(1);
- //TODO: add copy action;
- if (mShowEditAction) {
- ActionRow.Action action = mActionFactory.createEditButton();
- if (action != null) {
- actions.add(action);
- }
- }
- return actions;
- }
}
diff --git a/java/src/com/android/intentresolver/widget/ScrollableImagePreviewView.kt b/java/src/com/android/intentresolver/widget/ScrollableImagePreviewView.kt
index e761c0aa..9c948bd9 100644
--- a/java/src/com/android/intentresolver/widget/ScrollableImagePreviewView.kt
+++ b/java/src/com/android/intentresolver/widget/ScrollableImagePreviewView.kt
@@ -237,9 +237,14 @@ class ScrollableImagePreviewView : RecyclerView, ImagePreviewView {
internal constructor(
val type: PreviewType,
val uri: Uri,
+ val editAction: Runnable?,
internal var aspectRatioString: String
) {
- constructor(type: PreviewType, uri: Uri) : this(type, uri, "1:1")
+ constructor(
+ type: PreviewType,
+ uri: Uri,
+ editAction: Runnable?
+ ) : this(type, uri, editAction, "1:1")
}
enum class PreviewType {
@@ -370,6 +375,7 @@ class ScrollableImagePreviewView : RecyclerView, ImagePreviewView {
val image = view.requireViewById<ImageView>(R.id.image)
private val badgeFrame = view.requireViewById<View>(R.id.badge_frame)
private val badge = view.requireViewById<ImageView>(R.id.badge)
+ private val editActionContainer = view.findViewById<View?>(R.id.edit)
private var scope: CoroutineScope? = null
fun bind(
@@ -404,6 +410,12 @@ class ScrollableImagePreviewView : RecyclerView, ImagePreviewView {
badgeFrame.visibility = View.VISIBLE
}
}
+ preview.editAction?.also { onClick ->
+ editActionContainer?.apply {
+ setOnClickListener { onClick.run() }
+ visibility = View.VISIBLE
+ }
+ }
resetScope().launch {
loadImage(preview, imageLoader)
if (preview.type == PreviewType.Image) {
@@ -545,7 +557,8 @@ class ScrollableImagePreviewView : RecyclerView, ImagePreviewView {
bitmap.width,
bitmap.height
)
- } ?: 0
+ }
+ ?: 0
}
.getOrDefault(0)
diff --git a/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java b/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java
index c2212bc2..99564ae3 100644
--- a/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java
+++ b/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java
@@ -868,8 +868,8 @@ public class UnbundledChooserActivityTest {
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- onView(withId(com.android.internal.R.id.chooser_copy_button)).check(matches(isDisplayed()));
- onView(withId(com.android.internal.R.id.chooser_copy_button)).perform(click());
+ onView(withId(R.id.copy)).check(matches(isDisplayed()));
+ onView(withId(R.id.copy)).perform(click());
ClipboardManager clipboard = (ClipboardManager) activity.getSystemService(
Context.CLIPBOARD_SERVICE);
ClipData clipData = clipboard.getPrimaryClip();
@@ -892,8 +892,8 @@ public class UnbundledChooserActivityTest {
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- onView(withId(com.android.internal.R.id.chooser_copy_button)).check(matches(isDisplayed()));
- onView(withId(com.android.internal.R.id.chooser_copy_button)).perform(click());
+ onView(withId(R.id.copy)).check(matches(isDisplayed()));
+ onView(withId(R.id.copy)).perform(click());
ChooserActivityLogger logger = activity.getChooserActivityLogger();
verify(logger, times(1)).logActionSelected(eq(ChooserActivityLogger.SELECTION_TYPE_COPY));
diff --git a/java/tests/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUiTest.kt b/java/tests/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUiTest.kt
index c62f36ce..9bfd2052 100644
--- a/java/tests/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUiTest.kt
+++ b/java/tests/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUiTest.kt
@@ -51,8 +51,8 @@ class ChooserContentPreviewUiTest {
}
private val actionFactory =
object : ActionFactory {
- override fun createCopyButton() = ActionRow.Action(label = "Copy", icon = null) {}
- override fun createEditButton(): ActionRow.Action? = null
+ override fun getCopyButtonRunnable(): Runnable? = null
+ override fun getEditButtonRunnable(): Runnable? = null
override fun createCustomActions(): List<ActionRow.Action> = emptyList()
override fun getModifyShareAction(): ActionRow.Action? = null
override fun getExcludeSharedTextAction(): Consumer<Boolean> = Consumer<Boolean> {}
@@ -103,12 +103,7 @@ class ChooserContentPreviewUiTest {
whenever(previewData.previewType).thenReturn(ContentPreviewType.CONTENT_PREVIEW_IMAGE)
whenever(previewData.uriCount).thenReturn(2)
whenever(previewData.firstFileInfo)
- .thenReturn(
- FileInfo.Builder(uri)
- .withPreviewUri(uri)
- .withMimeType("image/png")
- .build()
- )
+ .thenReturn(FileInfo.Builder(uri).withPreviewUri(uri).withMimeType("image/png").build())
val testSubject =
ChooserContentPreviewUi(
lifecycle,
@@ -131,12 +126,7 @@ class ChooserContentPreviewUiTest {
whenever(previewData.previewType).thenReturn(ContentPreviewType.CONTENT_PREVIEW_IMAGE)
whenever(previewData.uriCount).thenReturn(2)
whenever(previewData.firstFileInfo)
- .thenReturn(
- FileInfo.Builder(uri)
- .withPreviewUri(uri)
- .withMimeType("image/png")
- .build()
- )
+ .thenReturn(FileInfo.Builder(uri).withPreviewUri(uri).withMimeType("image/png").build())
val testSubject =
ChooserContentPreviewUi(
lifecycle,
diff --git a/java/tests/src/com/android/intentresolver/contentpreview/ContentPreviewUiTest.kt b/java/tests/src/com/android/intentresolver/contentpreview/ContentPreviewUiTest.kt
index 6c30fc9e..6db53a9e 100644
--- a/java/tests/src/com/android/intentresolver/contentpreview/ContentPreviewUiTest.kt
+++ b/java/tests/src/com/android/intentresolver/contentpreview/ContentPreviewUiTest.kt
@@ -16,41 +16,18 @@
package com.android.intentresolver.contentpreview
-import android.content.res.Resources
-import android.view.LayoutInflater
-import android.view.ViewGroup
-import com.android.intentresolver.widget.ActionRow
import com.android.intentresolver.widget.ScrollableImagePreviewView.PreviewType
import com.google.common.truth.Truth.assertThat
import org.junit.Test
class ContentPreviewUiTest {
- private class TestablePreview() : ContentPreviewUi() {
- override fun getType() = 0
-
- override fun display(
- resources: Resources?,
- layoutInflater: LayoutInflater?,
- parent: ViewGroup?
- ): ViewGroup {
- throw IllegalStateException()
- }
-
- // exposing for testing
- fun makeActions(
- system: List<ActionRow.Action>,
- custom: List<ActionRow.Action>
- ): List<ActionRow.Action> {
- return createActions(system, custom)
- }
- }
-
@Test
fun testPreviewTypes() {
- val typeClassifier = object : MimeTypeClassifier {
- override fun isImageType(type: String?) = (type == "image")
- override fun isVideoType(type: String?) = (type == "video")
- }
+ val typeClassifier =
+ object : MimeTypeClassifier {
+ override fun isImageType(type: String?) = (type == "image")
+ override fun isVideoType(type: String?) = (type == "video")
+ }
assertThat(ContentPreviewUi.getPreviewType(typeClassifier, "image"))
.isEqualTo(PreviewType.Image)
@@ -61,15 +38,4 @@ class ContentPreviewUiTest {
assertThat(ContentPreviewUi.getPreviewType(typeClassifier, null))
.isEqualTo(PreviewType.File)
}
-
- @Test
- fun testCreateActions() {
- val preview = TestablePreview()
-
- val system = listOf(ActionRow.Action(label="system", icon=null) {})
- val custom = listOf(ActionRow.Action(label="custom", icon=null) {})
-
- assertThat(preview.makeActions(system, custom)).isEqualTo(custom)
- assertThat(preview.makeActions(system, listOf())).isEqualTo(system)
- }
}
diff --git a/java/tests/src/com/android/intentresolver/widget/BatchPreviewLoaderTest.kt b/java/tests/src/com/android/intentresolver/widget/BatchPreviewLoaderTest.kt
index c1d7451f..e65cba5f 100644
--- a/java/tests/src/com/android/intentresolver/widget/BatchPreviewLoaderTest.kt
+++ b/java/tests/src/com/android/intentresolver/widget/BatchPreviewLoaderTest.kt
@@ -18,29 +18,29 @@ package com.android.intentresolver.widget
import android.graphics.Bitmap
import android.net.Uri
+import com.android.intentresolver.captureMany
+import com.android.intentresolver.mock
import com.android.intentresolver.widget.ScrollableImagePreviewView.BatchPreviewLoader
import com.android.intentresolver.widget.ScrollableImagePreviewView.Preview
import com.android.intentresolver.widget.ScrollableImagePreviewView.PreviewType
+import com.android.intentresolver.withArgCaptor
+import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.launch
-import kotlinx.coroutines.cancel
import kotlinx.coroutines.test.UnconfinedTestDispatcher
-import org.junit.Test
-import com.android.intentresolver.mock
-import com.android.intentresolver.captureMany
-import com.android.intentresolver.withArgCaptor
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.setMain
import org.junit.After
import org.junit.Before
+import org.junit.Test
import org.mockito.Mockito.atLeast
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
-import com.google.common.truth.Truth.assertThat
@OptIn(ExperimentalCoroutinesApi::class)
class BatchPreviewLoaderTest {
@@ -67,22 +67,21 @@ class BatchPreviewLoaderTest {
val uriOne = createUri(1)
val uriTwo = createUri(2)
imageLoader.setUriLoadingOrder(succeed(uriTwo), succeed(uriOne))
- val testSubject = BatchPreviewLoader(
- imageLoader,
- previews(uriOne, uriTwo),
- 0,
- onReset,
- onUpdate,
- onCompletion
- )
+ val testSubject =
+ BatchPreviewLoader(
+ imageLoader,
+ previews(uriOne, uriTwo),
+ 0,
+ onReset,
+ onUpdate,
+ onCompletion
+ )
testSubject.loadAspectRatios(200) { _, _, _ -> 100 }
dispatcher.scheduler.advanceUntilIdle()
verify(onCompletion, times(1)).invoke()
verify(onReset, times(1)).invoke(2)
- val list = withArgCaptor {
- verify(onUpdate, times(1)).invoke(capture())
- }.map { it.uri }
+ val list = withArgCaptor { verify(onUpdate, times(1)).invoke(capture()) }.map { it.uri }
assertThat(list).containsExactly(uriOne, uriTwo).inOrder()
}
@@ -93,22 +92,21 @@ class BatchPreviewLoaderTest {
val uriTwo = createUri(2)
val uriThree = createUri(3)
imageLoader.setUriLoadingOrder(succeed(uriThree), fail(uriTwo), succeed(uriOne))
- val testSubject = BatchPreviewLoader(
- imageLoader,
- previews(uriOne, uriTwo, uriThree),
- 0,
- onReset,
- onUpdate,
- onCompletion
- )
+ val testSubject =
+ BatchPreviewLoader(
+ imageLoader,
+ previews(uriOne, uriTwo, uriThree),
+ 0,
+ onReset,
+ onUpdate,
+ onCompletion
+ )
testSubject.loadAspectRatios(200) { _, _, _ -> 100 }
dispatcher.scheduler.advanceUntilIdle()
verify(onCompletion, times(1)).invoke()
verify(onReset, times(1)).invoke(3)
- val list = withArgCaptor {
- verify(onUpdate, times(1)).invoke(capture())
- }.map { it.uri }
+ val list = withArgCaptor { verify(onUpdate, times(1)).invoke(capture()) }.map { it.uri }
assertThat(list).containsExactly(uriOne, uriThree).inOrder()
}
@@ -116,35 +114,28 @@ class BatchPreviewLoaderTest {
fun test_imagesLoadedNotInOrder_updatedInOrder() {
val imageLoader = TestImageLoader(testScope)
val uris = Array(10) { createUri(it) }
- val loadingOrder = Array(uris.size) { i ->
- val uriIdx = when {
- i % 2 == 1 -> i - 1
- i % 2 == 0 && i < uris.size - 1 -> i + 1
- else -> i
+ val loadingOrder =
+ Array(uris.size) { i ->
+ val uriIdx =
+ when {
+ i % 2 == 1 -> i - 1
+ i % 2 == 0 && i < uris.size - 1 -> i + 1
+ else -> i
+ }
+ succeed(uris[uriIdx])
}
- succeed(uris[uriIdx])
- }
imageLoader.setUriLoadingOrder(*loadingOrder)
- val testSubject = BatchPreviewLoader(
- imageLoader,
- previews(*uris),
- 0,
- onReset,
- onUpdate,
- onCompletion
- )
+ val testSubject =
+ BatchPreviewLoader(imageLoader, previews(*uris), 0, onReset, onUpdate, onCompletion)
testSubject.loadAspectRatios(200) { _, _, _ -> 100 }
dispatcher.scheduler.advanceUntilIdle()
verify(onCompletion, times(1)).invoke()
verify(onReset, times(1)).invoke(uris.size)
- val list = captureMany {
- verify(onUpdate, atLeast(1)).invoke(capture())
- }.fold(ArrayList<Preview>()) { acc, update ->
- acc.apply {
- addAll(update)
- }
- }.map { it.uri }
+ val list =
+ captureMany { verify(onUpdate, atLeast(1)).invoke(capture()) }
+ .fold(ArrayList<Preview>()) { acc, update -> acc.apply { addAll(update) } }
+ .map { it.uri }
assertThat(list).containsExactly(*uris).inOrder()
}
@@ -152,36 +143,29 @@ class BatchPreviewLoaderTest {
fun test_imagesLoadedNotInOrderSomeFailed_updatedInOrder() {
val imageLoader = TestImageLoader(testScope)
val uris = Array(10) { createUri(it) }
- val loadingOrder = Array(uris.size) { i ->
- val uriIdx = when {
- i % 2 == 1 -> i - 1
- i % 2 == 0 && i < uris.size - 1 -> i + 1
- else -> i
+ val loadingOrder =
+ Array(uris.size) { i ->
+ val uriIdx =
+ when {
+ i % 2 == 1 -> i - 1
+ i % 2 == 0 && i < uris.size - 1 -> i + 1
+ else -> i
+ }
+ if (uriIdx % 2 == 0) fail(uris[uriIdx]) else succeed(uris[uriIdx])
}
- if (uriIdx % 2 == 0) fail(uris[uriIdx]) else succeed(uris[uriIdx])
- }
val expectedUris = Array(uris.size / 2) { createUri(it * 2 + 1) }
imageLoader.setUriLoadingOrder(*loadingOrder)
- val testSubject = BatchPreviewLoader(
- imageLoader,
- previews(*uris),
- 0,
- onReset,
- onUpdate,
- onCompletion
- )
+ val testSubject =
+ BatchPreviewLoader(imageLoader, previews(*uris), 0, onReset, onUpdate, onCompletion)
testSubject.loadAspectRatios(200) { _, _, _ -> 100 }
dispatcher.scheduler.advanceUntilIdle()
verify(onCompletion, times(1)).invoke()
verify(onReset, times(1)).invoke(uris.size)
- val list = captureMany {
- verify(onUpdate, atLeast(1)).invoke(capture())
- }.fold(ArrayList<Preview>()) { acc, update ->
- acc.apply {
- addAll(update)
- }
- }.map { it.uri }
+ val list =
+ captureMany { verify(onUpdate, atLeast(1)).invoke(capture()) }
+ .fold(ArrayList<Preview>()) { acc, update -> acc.apply { addAll(update) } }
+ .map { it.uri }
assertThat(list).containsExactly(*expectedUris).inOrder()
}
@@ -191,21 +175,15 @@ class BatchPreviewLoaderTest {
private fun succeed(uri: Uri) = uri to true
private fun previews(vararg uris: Uri) =
uris.fold(ArrayList<Preview>(uris.size)) { acc, uri ->
- acc.apply {
- add(Preview(PreviewType.Image, uri))
- }
+ acc.apply { add(Preview(PreviewType.Image, uri, editAction = null)) }
}
}
-private class TestImageLoader(
- scope: CoroutineScope
-) : suspend (Uri, Boolean) -> Bitmap? {
+private class TestImageLoader(scope: CoroutineScope) : suspend (Uri, Boolean) -> Bitmap? {
private val loadingOrder = ArrayDeque<Pair<Uri, Boolean>>()
private val pendingRequests = LinkedHashMap<Uri, CompletableDeferred<Bitmap?>>()
private val flow = MutableSharedFlow<Unit>(replay = 1)
- private val bitmap by lazy {
- Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888)
- }
+ private val bitmap by lazy { Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888) }
init {
scope.launch {
@@ -217,9 +195,7 @@ private class TestImageLoader(
deferred.complete(if (isLoaded) bitmap else null)
}
if (loadingOrder.isEmpty()) {
- pendingRequests.forEach { (uri, deferred) ->
- deferred.complete(bitmap)
- }
+ pendingRequests.forEach { (uri, deferred) -> deferred.complete(bitmap) }
pendingRequests.clear()
}
}