diff options
Diffstat (limited to 'java')
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) + } +} |