summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
Diffstat (limited to 'java')
-rw-r--r--java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java1
-rw-r--r--java/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUi.java46
-rw-r--r--java/tests/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUiTest.kt225
3 files changed, 255 insertions, 17 deletions
diff --git a/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java
index 18cbb8af..d4874cac 100644
--- a/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java
+++ b/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java
@@ -150,6 +150,7 @@ public final class ChooserContentPreviewUi {
isSingleImageShare,
previewData.getUriCount(),
targetIntent.getCharSequenceExtra(Intent.EXTRA_TEXT),
+ targetIntent.getType(),
actionFactory,
imageLoader,
typeClassifier,
diff --git a/java/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUi.java
index 35990990..6e1212e9 100644
--- a/java/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUi.java
+++ b/java/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUi.java
@@ -49,6 +49,8 @@ import java.util.function.Consumer;
*/
class FilesPlusTextContentPreviewUi extends ContentPreviewUi {
private final Lifecycle mLifecycle;
+ @Nullable
+ private final String mIntentMimeType;
private final CharSequence mText;
private final ChooserContentPreviewUi.ActionFactory mActionFactory;
private final ImageLoader mImageLoader;
@@ -70,15 +72,17 @@ class FilesPlusTextContentPreviewUi extends ContentPreviewUi {
boolean isSingleImage,
int fileCount,
CharSequence text,
+ @Nullable String intentMimeType,
ChooserContentPreviewUi.ActionFactory actionFactory,
ImageLoader imageLoader,
MimeTypeClassifier typeClassifier,
HeadlineGenerator headlineGenerator) {
- mLifecycle = lifecycle;
if (isSingleImage && fileCount != 1) {
throw new IllegalArgumentException(
"fileCount = " + fileCount + " and isSingleImage = true");
}
+ mLifecycle = lifecycle;
+ mIntentMimeType = intentMimeType;
mFileCount = fileCount;
mIsSingleImage = isSingleImage;
mText = text;
@@ -127,18 +131,25 @@ class FilesPlusTextContentPreviewUi extends ContentPreviewUi {
List<ActionRow.Action> actions = mActionFactory.createCustomActions();
actionRow.setActions(actions);
+ if (!mIsSingleImage) {
+ mContentPreviewView.requireViewById(R.id.image_view).setVisibility(View.GONE);
+ }
+ prepareTextPreview(mContentPreviewView, mActionFactory);
if (mIsMetadataUpdated) {
updateUiWithMetadata(mContentPreviewView);
- } else if (!mIsSingleImage) {
- mContentPreviewView.requireViewById(R.id.image_view).setVisibility(View.GONE);
+ } else {
+ updateHeadline(
+ mContentPreviewView,
+ mFileCount,
+ mTypeClassifier.isImageType(mIntentMimeType),
+ mTypeClassifier.isVideoType(mIntentMimeType));
}
return mContentPreviewView;
}
private void updateUiWithMetadata(ViewGroup contentPreviewView) {
- prepareTextPreview(contentPreviewView, mActionFactory);
- updateHeadline(contentPreviewView);
+ updateHeadline(contentPreviewView, mFileCount, mAllImages, mAllVideos);
ImageView imagePreview = mContentPreviewView.requireViewById(R.id.image_view);
if (mIsSingleImage && mFirstFilePreviewUri != null) {
@@ -157,24 +168,25 @@ class FilesPlusTextContentPreviewUi extends ContentPreviewUi {
}
}
- private void updateHeadline(ViewGroup contentPreview) {
+ private void updateHeadline(
+ ViewGroup contentPreview, int fileCount, boolean allImages, boolean allVideos) {
CheckBox includeText = contentPreview.requireViewById(R.id.include_text_action);
String headline;
if (includeText.getVisibility() == View.VISIBLE && includeText.isChecked()) {
- if (mAllImages) {
- headline = mHeadlineGenerator.getImagesWithTextHeadline(mText, mFileCount);
- } else if (mAllVideos) {
- headline = mHeadlineGenerator.getVideosWithTextHeadline(mText, mFileCount);
+ if (allImages) {
+ headline = mHeadlineGenerator.getImagesWithTextHeadline(mText, fileCount);
+ } else if (allVideos) {
+ headline = mHeadlineGenerator.getVideosWithTextHeadline(mText, fileCount);
} else {
- headline = mHeadlineGenerator.getFilesWithTextHeadline(mText, mFileCount);
+ headline = mHeadlineGenerator.getFilesWithTextHeadline(mText, fileCount);
}
} else {
- if (mAllImages) {
- headline = mHeadlineGenerator.getImagesHeadline(mFileCount);
- } else if (mAllVideos) {
- headline = mHeadlineGenerator.getVideosHeadline(mFileCount);
+ if (allImages) {
+ headline = mHeadlineGenerator.getImagesHeadline(fileCount);
+ } else if (allVideos) {
+ headline = mHeadlineGenerator.getVideosHeadline(fileCount);
} else {
- headline = mHeadlineGenerator.getFilesHeadline(mFileCount);
+ headline = mHeadlineGenerator.getFilesHeadline(fileCount);
}
}
@@ -201,7 +213,7 @@ class FilesPlusTextContentPreviewUi extends ContentPreviewUi {
textView.setText(getNoTextString(contentPreview.getResources()));
}
shareTextAction.accept(!isChecked);
- updateHeadline(contentPreview);
+ updateHeadline(contentPreview, mFileCount, mAllImages, mAllVideos);
});
if (SHOW_TOGGLE_CHECKMARK) {
includeText.setVisibility(View.VISIBLE);
diff --git a/java/tests/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUiTest.kt b/java/tests/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUiTest.kt
new file mode 100644
index 00000000..06ade1ce
--- /dev/null
+++ b/java/tests/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUiTest.kt
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+package com.android.intentresolver.contentpreview
+
+import android.net.Uri
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.intentresolver.R
+import com.android.intentresolver.TestLifecycleOwner
+import com.android.intentresolver.mock
+import com.android.intentresolver.whenever
+import com.android.intentresolver.widget.ActionRow
+import com.google.common.truth.Truth.assertThat
+import java.util.function.Consumer
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+
+private const val HEADLINE_IMAGES = "Image Headline"
+private const val HEADLINE_VIDEOS = "Video Headline"
+private const val HEADLINE_FILES = "Files Headline"
+private const val SHARED_TEXT = "Some text to share"
+
+@RunWith(AndroidJUnit4::class)
+class FilesPlusTextContentPreviewUiTest {
+ private val lifecycleOwner = TestLifecycleOwner()
+ private val actionFactory =
+ object : ChooserContentPreviewUi.ActionFactory {
+ override fun getEditButtonRunnable(): Runnable? = null
+ override fun getCopyButtonRunnable(): Runnable? = null
+ override fun createCustomActions(): List<ActionRow.Action> = emptyList()
+ override fun getModifyShareAction(): ActionRow.Action? = null
+ override fun getExcludeSharedTextAction(): Consumer<Boolean> = Consumer<Boolean> {}
+ }
+ private val imageLoader = mock<ImageLoader>()
+ private val headlineGenerator =
+ mock<HeadlineGenerator> {
+ whenever(getImagesHeadline(anyInt())).thenReturn(HEADLINE_IMAGES)
+ whenever(getVideosHeadline(anyInt())).thenReturn(HEADLINE_VIDEOS)
+ whenever(getFilesHeadline(anyInt())).thenReturn(HEADLINE_FILES)
+ }
+
+ private val context
+ get() = getInstrumentation().getContext()
+
+ @Test
+ fun test_displayImagesPlusTextWithoutUriMetadata_showImagesHeadline() {
+ val sharedFileCount = 2
+ val previewView = testLoadingHeadline("image/*", sharedFileCount)
+
+ verify(headlineGenerator, times(1)).getImagesHeadline(sharedFileCount)
+ verifyPreviewHeadline(previewView, HEADLINE_IMAGES)
+ verifySharedText(previewView)
+ }
+
+ @Test
+ fun test_displayVideosPlusTextWithoutUriMetadata_showVideosHeadline() {
+ val sharedFileCount = 2
+ val previewView = testLoadingHeadline("video/*", sharedFileCount)
+
+ verify(headlineGenerator, times(1)).getVideosHeadline(sharedFileCount)
+ verifyPreviewHeadline(previewView, HEADLINE_VIDEOS)
+ verifySharedText(previewView)
+ }
+
+ @Test
+ fun test_displayDocsPlusTextWithoutUriMetadata_showFilesHeadline() {
+ val sharedFileCount = 2
+ val previewView = testLoadingHeadline("application/pdf", sharedFileCount)
+
+ verify(headlineGenerator, times(1)).getFilesHeadline(sharedFileCount)
+ verifyPreviewHeadline(previewView, HEADLINE_FILES)
+ verifySharedText(previewView)
+ }
+
+ @Test
+ fun test_displayMixedContentPlusTextWithoutUriMetadata_showFilesHeadline() {
+ val sharedFileCount = 2
+ val previewView = testLoadingHeadline("*/*", sharedFileCount)
+
+ verify(headlineGenerator, times(1)).getFilesHeadline(sharedFileCount)
+ verifyPreviewHeadline(previewView, HEADLINE_FILES)
+ verifySharedText(previewView)
+ }
+
+ @Test
+ fun test_displayImagesPlusTextWithUriMetadataSet_showImagesHeadline() {
+ val loadedFileMetadata = createFileInfosWithMimeTypes("image/png", "image/jpeg")
+ val sharedFileCount = loadedFileMetadata.size
+ val previewView = testLoadingHeadline("image/*", sharedFileCount, loadedFileMetadata)
+
+ verify(headlineGenerator, times(1)).getImagesHeadline(sharedFileCount)
+ verifyPreviewHeadline(previewView, HEADLINE_IMAGES)
+ verifySharedText(previewView)
+ }
+
+ @Test
+ fun test_displayVideosPlusTextWithUriMetadataSet_showVideosHeadline() {
+ val loadedFileMetadata = createFileInfosWithMimeTypes("video/mp4", "video/mp4")
+ val sharedFileCount = loadedFileMetadata.size
+ val previewView = testLoadingHeadline("video/*", sharedFileCount, loadedFileMetadata)
+
+ verify(headlineGenerator, times(1)).getVideosHeadline(sharedFileCount)
+ verifyPreviewHeadline(previewView, HEADLINE_VIDEOS)
+ verifySharedText(previewView)
+ }
+
+ @Test
+ fun test_displayImagesAndVideosPlusTextWithUriMetadataSet_showFilesHeadline() {
+ val loadedFileMetadata = createFileInfosWithMimeTypes("image/png", "video/mp4")
+ val sharedFileCount = loadedFileMetadata.size
+ val previewView = testLoadingHeadline("*/*", sharedFileCount, loadedFileMetadata)
+
+ verify(headlineGenerator, times(1)).getFilesHeadline(sharedFileCount)
+ verifyPreviewHeadline(previewView, HEADLINE_FILES)
+ verifySharedText(previewView)
+ }
+
+ @Test
+ fun test_displayDocsPlusTextWithUriMetadataSet_showFilesHeadline() {
+ val loadedFileMetadata = createFileInfosWithMimeTypes("application/pdf", "application/pdf")
+ val sharedFileCount = loadedFileMetadata.size
+ val previewView =
+ testLoadingHeadline("application/pdf", sharedFileCount, loadedFileMetadata)
+
+ verify(headlineGenerator, times(1)).getFilesHeadline(sharedFileCount)
+ verifyPreviewHeadline(previewView, HEADLINE_FILES)
+ verifySharedText(previewView)
+ }
+
+ @Test
+ fun test_uriMetadataIsMoreSpecificThanIntentMimeType_headlineGetsUpdated() {
+ val sharedFileCount = 2
+ val testSubject =
+ FilesPlusTextContentPreviewUi(
+ lifecycleOwner.lifecycle,
+ /*isSingleImage=*/ false,
+ sharedFileCount,
+ SHARED_TEXT,
+ /*intentMimeType=*/ "*/*",
+ actionFactory,
+ imageLoader,
+ DefaultMimeTypeClassifier,
+ headlineGenerator
+ )
+ val layoutInflater = LayoutInflater.from(context)
+ val gridLayout = layoutInflater.inflate(R.layout.chooser_grid, null, false) as ViewGroup
+
+ val previewView =
+ testSubject.display(context.resources, LayoutInflater.from(context), gridLayout)
+
+ verify(headlineGenerator, times(1)).getFilesHeadline(sharedFileCount)
+ verify(headlineGenerator, never()).getImagesHeadline(sharedFileCount)
+ verifyPreviewHeadline(previewView, HEADLINE_FILES)
+
+ testSubject.updatePreviewMetadata(createFileInfosWithMimeTypes("image/png", "image/jpg"))
+
+ verify(headlineGenerator, times(1)).getFilesHeadline(sharedFileCount)
+ verify(headlineGenerator, times(1)).getImagesHeadline(sharedFileCount)
+ verifyPreviewHeadline(previewView, HEADLINE_IMAGES)
+ }
+
+ private fun testLoadingHeadline(
+ intentMimeType: String,
+ sharedFileCount: Int,
+ loadedFileMetadata: List<FileInfo>? = null
+ ): ViewGroup? {
+ val testSubject =
+ FilesPlusTextContentPreviewUi(
+ lifecycleOwner.lifecycle,
+ /*isSingleImage=*/ false,
+ sharedFileCount,
+ SHARED_TEXT,
+ intentMimeType,
+ actionFactory,
+ imageLoader,
+ DefaultMimeTypeClassifier,
+ headlineGenerator
+ )
+ val layoutInflater = LayoutInflater.from(context)
+ val gridLayout = layoutInflater.inflate(R.layout.chooser_grid, null, false) as ViewGroup
+
+ loadedFileMetadata?.let(testSubject::updatePreviewMetadata)
+ return testSubject.display(context.resources, LayoutInflater.from(context), gridLayout)
+ }
+
+ private fun createFileInfosWithMimeTypes(vararg mimeTypes: String): List<FileInfo> {
+ val uri = Uri.parse("content://pkg.app/file")
+ return mimeTypes.map { mimeType -> FileInfo.Builder(uri).withMimeType(mimeType).build() }
+ }
+
+ private fun verifyPreviewHeadline(previewView: ViewGroup?, expectedText: String) {
+ assertThat(previewView).isNotNull()
+ val headlineView = previewView?.findViewById<TextView>(R.id.headline)
+ assertThat(headlineView).isNotNull()
+ assertThat(headlineView?.text).isEqualTo(expectedText)
+ }
+
+ private fun verifySharedText(previewView: ViewGroup?) {
+ assertThat(previewView).isNotNull()
+ val textContentView = previewView?.findViewById<TextView>(R.id.content_preview_text)
+ assertThat(textContentView).isNotNull()
+ assertThat(textContentView?.text).isEqualTo(SHARED_TEXT)
+ }
+}