diff options
16 files changed, 211 insertions, 45 deletions
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml index f98f5cd1..5c1210b7 100644 --- a/java/res/values/strings.xml +++ b/java/res/values/strings.xml @@ -210,6 +210,11 @@ } </string> + + <!-- Title atop a sharing UI indicating that an album (typically of photos/videos) is being + shared [CHAR_LIMIT=50] --> + <string name="sharing_album">Sharing album</string> + <!-- Message indicating that the attached text has been removed from this share and only the images are being shared. [CHAR LIMIT=none] --> <string name="sharing_images_only">{count, plural, diff --git a/java/src/com/android/intentresolver/ChooserActivity.java b/java/src/com/android/intentresolver/ChooserActivity.java index c3b13527..708538de 100644 --- a/java/src/com/android/intentresolver/ChooserActivity.java +++ b/java/src/com/android/intentresolver/ChooserActivity.java @@ -310,7 +310,8 @@ public class ChooserActivity extends Hilt_ChooserActivity implements previewViewModel.getImageLoader(), createChooserActionFactory(), mEnterTransitionAnimationDelegate, - new HeadlineGeneratorImpl(this)); + new HeadlineGeneratorImpl(this), + ContentTypeHint.NONE); updateStickyContentPreview(); if (shouldShowStickyContentPreview() diff --git a/java/src/com/android/intentresolver/ContentTypeHint.kt b/java/src/com/android/intentresolver/ContentTypeHint.kt new file mode 100644 index 00000000..f607e4ae --- /dev/null +++ b/java/src/com/android/intentresolver/ContentTypeHint.kt @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2024 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 + +import android.content.Intent + +/** Enum reflecting the value of [Intent.EXTRA_CHOOSER_CONTENT_TYPE_HINT]. */ +enum class ContentTypeHint { + NONE, + ALBUM, +} diff --git a/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java index a015147d..5b4cb682 100644 --- a/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java +++ b/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java @@ -32,6 +32,7 @@ import android.view.ViewGroup; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; +import com.android.intentresolver.ContentTypeHint; import com.android.intentresolver.widget.ActionRow; import com.android.intentresolver.widget.ImagePreviewView.TransitionElementStatusCallback; @@ -98,7 +99,8 @@ public final class ChooserContentPreviewUi { ImageLoader imageLoader, ActionFactory actionFactory, TransitionElementStatusCallback transitionElementStatusCallback, - HeadlineGenerator headlineGenerator) { + HeadlineGenerator headlineGenerator, + ContentTypeHint contentTypeHint) { mScope = scope; mContentPreviewUi = createContentPreview( previewData, @@ -107,7 +109,8 @@ public final class ChooserContentPreviewUi { imageLoader, actionFactory, transitionElementStatusCallback, - headlineGenerator); + headlineGenerator, + contentTypeHint); if (mContentPreviewUi.getType() != CONTENT_PREVIEW_IMAGE) { transitionElementStatusCallback.onAllTransitionElementsReady(); } @@ -120,7 +123,8 @@ public final class ChooserContentPreviewUi { ImageLoader imageLoader, ActionFactory actionFactory, TransitionElementStatusCallback transitionElementStatusCallback, - HeadlineGenerator headlineGenerator) { + HeadlineGenerator headlineGenerator, + ContentTypeHint contentTypeHint) { int previewType = previewData.getPreviewType(); if (previewType == CONTENT_PREVIEW_TEXT) { @@ -129,7 +133,8 @@ public final class ChooserContentPreviewUi { targetIntent, actionFactory, imageLoader, - headlineGenerator); + headlineGenerator, + contentTypeHint); } if (previewType == CONTENT_PREVIEW_FILE) { FileContentPreviewUi fileContentPreviewUi = new FileContentPreviewUi( @@ -142,7 +147,7 @@ public final class ChooserContentPreviewUi { return fileContentPreviewUi; } boolean isSingleImageShare = previewData.getUriCount() == 1 - && typeClassifier.isImageType(previewData.getFirstFileInfo().getMimeType()); + && typeClassifier.isImageType(previewData.getFirstFileInfo().getMimeType()); CharSequence text = targetIntent.getCharSequenceExtra(Intent.EXTRA_TEXT); if (!TextUtils.isEmpty(text)) { FilesPlusTextContentPreviewUi previewUi = @@ -200,7 +205,8 @@ public final class ChooserContentPreviewUi { Intent targetIntent, ChooserContentPreviewUi.ActionFactory actionFactory, ImageLoader imageLoader, - HeadlineGenerator headlineGenerator) { + HeadlineGenerator headlineGenerator, + ContentTypeHint contentTypeHint) { CharSequence sharingText = targetIntent.getCharSequenceExtra(Intent.EXTRA_TEXT); CharSequence previewTitle = targetIntent.getCharSequenceExtra(Intent.EXTRA_TITLE); ClipData previewData = targetIntent.getClipData(); @@ -211,6 +217,7 @@ public final class ChooserContentPreviewUi { previewThumbnail = previewDataItem.getUri(); } } + return new TextContentPreviewUi( scope, sharingText, @@ -218,6 +225,7 @@ public final class ChooserContentPreviewUi { previewThumbnail, actionFactory, imageLoader, - headlineGenerator); + headlineGenerator, + contentTypeHint); } } diff --git a/java/src/com/android/intentresolver/contentpreview/HeadlineGenerator.kt b/java/src/com/android/intentresolver/contentpreview/HeadlineGenerator.kt index 5f87c924..21308341 100644 --- a/java/src/com/android/intentresolver/contentpreview/HeadlineGenerator.kt +++ b/java/src/com/android/intentresolver/contentpreview/HeadlineGenerator.kt @@ -17,12 +17,14 @@ package com.android.intentresolver.contentpreview /** - * HeadlineGenerator generates the text to show at the top of the sharesheet as a brief - * description of the content being shared. + * HeadlineGenerator generates the text to show at the top of the sharesheet as a brief description + * of the content being shared. */ interface HeadlineGenerator { fun getTextHeadline(text: CharSequence): String + fun getAlbumHeadline(): String + fun getImagesWithTextHeadline(text: CharSequence, count: Int): String fun getVideosWithTextHeadline(text: CharSequence, count: Int): String diff --git a/java/src/com/android/intentresolver/contentpreview/HeadlineGeneratorImpl.kt b/java/src/com/android/intentresolver/contentpreview/HeadlineGeneratorImpl.kt index ef1e55d8..6e126822 100644 --- a/java/src/com/android/intentresolver/contentpreview/HeadlineGeneratorImpl.kt +++ b/java/src/com/android/intentresolver/contentpreview/HeadlineGeneratorImpl.kt @@ -34,6 +34,10 @@ class HeadlineGeneratorImpl(private val context: Context) : HeadlineGenerator { ) } + override fun getAlbumHeadline(): String { + return context.getString(R.string.sharing_album) + } + override fun getImagesWithTextHeadline(text: CharSequence, count: Int): String { return getPluralString( getTemplateResource( diff --git a/java/src/com/android/intentresolver/contentpreview/TextContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/TextContentPreviewUi.java index b0dc3c58..df2896d7 100644 --- a/java/src/com/android/intentresolver/contentpreview/TextContentPreviewUi.java +++ b/java/src/com/android/intentresolver/contentpreview/TextContentPreviewUi.java @@ -30,6 +30,7 @@ import android.widget.TextView; import androidx.annotation.Nullable; +import com.android.intentresolver.ContentTypeHint; import com.android.intentresolver.R; import com.android.intentresolver.widget.ActionRow; @@ -46,6 +47,7 @@ class TextContentPreviewUi extends ContentPreviewUi { private final ImageLoader mImageLoader; private final ChooserContentPreviewUi.ActionFactory mActionFactory; private final HeadlineGenerator mHeadlineGenerator; + private final ContentTypeHint mContentTypeHint; TextContentPreviewUi( CoroutineScope scope, @@ -54,7 +56,8 @@ class TextContentPreviewUi extends ContentPreviewUi { @Nullable Uri previewThumbnail, ChooserContentPreviewUi.ActionFactory actionFactory, ImageLoader imageLoader, - HeadlineGenerator headlineGenerator) { + HeadlineGenerator headlineGenerator, + ContentTypeHint contentTypeHint) { mScope = scope; mSharingText = sharingText; mPreviewTitle = previewTitle; @@ -62,6 +65,7 @@ class TextContentPreviewUi extends ContentPreviewUi { mImageLoader = imageLoader; mActionFactory = actionFactory; mHeadlineGenerator = headlineGenerator; + mContentTypeHint = contentTypeHint; } @Override @@ -139,7 +143,10 @@ class TextContentPreviewUi extends ContentPreviewUi { copyButton.setVisibility(View.GONE); } - displayHeadline(headlineViewParent, mHeadlineGenerator.getTextHeadline(mSharingText)); + String headlineText = (mContentTypeHint == ContentTypeHint.ALBUM) + ? mHeadlineGenerator.getAlbumHeadline() + : mHeadlineGenerator.getTextHeadline(mSharingText); + displayHeadline(headlineViewParent, headlineText); return contentPreviewLayout; } diff --git a/java/src/com/android/intentresolver/v2/ChooserActivity.java b/java/src/com/android/intentresolver/v2/ChooserActivity.java index b9cf53b6..247f6529 100644 --- a/java/src/com/android/intentresolver/v2/ChooserActivity.java +++ b/java/src/com/android/intentresolver/v2/ChooserActivity.java @@ -477,7 +477,8 @@ public class ChooserActivity extends Hilt_ChooserActivity implements previewViewModel.getImageLoader(), createChooserActionFactory(), mEnterTransitionAnimationDelegate, - new HeadlineGeneratorImpl(this)); + new HeadlineGeneratorImpl(this), + chooserRequest.getContentTypeHint()); updateStickyContentPreview(); if (shouldShowStickyContentPreview() || mChooserMultiProfilePagerAdapter diff --git a/java/src/com/android/intentresolver/v2/ui/model/ChooserRequest.kt b/java/src/com/android/intentresolver/v2/ui/model/ChooserRequest.kt index 5c785675..4fc2e46a 100644 --- a/java/src/com/android/intentresolver/v2/ui/model/ChooserRequest.kt +++ b/java/src/com/android/intentresolver/v2/ui/model/ChooserRequest.kt @@ -27,6 +27,7 @@ import android.os.Bundle import android.service.chooser.ChooserAction import android.service.chooser.ChooserTarget import androidx.annotation.StringRes +import com.android.intentresolver.ContentTypeHint import com.android.intentresolver.v2.ext.hasAction const val ANDROID_APP_SCHEME = "android-app" @@ -169,6 +170,9 @@ data class ChooserRequest( /** Focused item index (from target intent's STREAM_EXTRA) */ val focusedItemPosition: Int = 0, + + /** Value for [Intent.EXTRA_CHOOSER_CONTENT_TYPE_HINT] on the incoming chooser intent. */ + val contentTypeHint: ContentTypeHint = ContentTypeHint.NONE ) { val referrerPackage = referrer?.takeIf { it.scheme == ANDROID_APP_SCHEME }?.authority diff --git a/java/src/com/android/intentresolver/v2/ui/viewmodel/ChooserRequestReader.kt b/java/src/com/android/intentresolver/v2/ui/viewmodel/ChooserRequestReader.kt index 167c441f..558e54c9 100644 --- a/java/src/com/android/intentresolver/v2/ui/viewmodel/ChooserRequestReader.kt +++ b/java/src/com/android/intentresolver/v2/ui/viewmodel/ChooserRequestReader.kt @@ -40,9 +40,10 @@ import android.net.Uri import android.os.Bundle import android.service.chooser.ChooserAction import android.service.chooser.ChooserTarget -import android.service.chooser.Flags import com.android.intentresolver.ChooserActivity +import com.android.intentresolver.ContentTypeHint import com.android.intentresolver.R +import com.android.intentresolver.inject.ChooserServiceFlags import com.android.intentresolver.util.hasValidIcon import com.android.intentresolver.v2.ext.hasAction import com.android.intentresolver.v2.ext.ifMatch @@ -72,7 +73,10 @@ internal fun Intent.maybeAddSendActionFlags() = addFlags(FLAG_ACTIVITY_MULTIPLE_TASK) } -fun readChooserRequest(launch: ActivityLaunch): ValidationResult<ChooserRequest> { +fun readChooserRequest( + launch: ActivityLaunch, + flags: ChooserServiceFlags +): ValidationResult<ChooserRequest> { val extras = launch.intent.extras ?: Bundle() @Suppress("DEPRECATION") return validateFrom(extras::get) { @@ -135,7 +139,7 @@ fun readChooserRequest(launch: ActivityLaunch): ValidationResult<ChooserRequest> val additionalContentUri: Uri? val focusedItemPos: Int - if (isSendAction && Flags.chooserPayloadToggling()) { + if (isSendAction && flags.chooserPayloadToggling()) { additionalContentUri = optional(value<Uri>(EXTRA_CHOOSER_ADDITIONAL_CONTENT_URI)) focusedItemPos = optional(value<Int>(EXTRA_CHOOSER_FOCUSED_ITEM_POSITION)) ?: 0 } else { @@ -143,6 +147,16 @@ fun readChooserRequest(launch: ActivityLaunch): ValidationResult<ChooserRequest> focusedItemPos = 0 } + val contentTypeHint = + if (flags.chooserAlbumText()) { + when (optional(value<Int>(Intent.EXTRA_CHOOSER_CONTENT_TYPE_HINT))) { + Intent.CHOOSER_CONTENT_TYPE_ALBUM -> ContentTypeHint.ALBUM + else -> ContentTypeHint.NONE + } + } else { + ContentTypeHint.NONE + } + ChooserRequest( targetIntent = targetIntent, targetAction = targetIntent.action, @@ -169,6 +183,7 @@ fun readChooserRequest(launch: ActivityLaunch): ValidationResult<ChooserRequest> shareTargetFilter = targetIntent.toShareTargetFilter(), additionalContentUri = additionalContentUri, focusedItemPosition = focusedItemPos, + contentTypeHint = contentTypeHint, ) } } diff --git a/java/src/com/android/intentresolver/v2/ui/viewmodel/ChooserViewModel.kt b/java/src/com/android/intentresolver/v2/ui/viewmodel/ChooserViewModel.kt index 17b1e664..776bc1cb 100644 --- a/java/src/com/android/intentresolver/v2/ui/viewmodel/ChooserViewModel.kt +++ b/java/src/com/android/intentresolver/v2/ui/viewmodel/ChooserViewModel.kt @@ -18,6 +18,7 @@ package com.android.intentresolver.v2.ui.viewmodel import android.util.Log import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel +import com.android.intentresolver.inject.ChooserServiceFlags import com.android.intentresolver.v2.ui.model.ActivityLaunch import com.android.intentresolver.v2.ui.model.ActivityLaunch.Companion.ACTIVITY_LAUNCH_KEY import com.android.intentresolver.v2.ui.model.ChooserRequest @@ -28,7 +29,8 @@ import javax.inject.Inject private const val TAG = "ChooserViewModel" @HiltViewModel -class ChooserViewModel @Inject constructor(args: SavedStateHandle) : ViewModel() { +class ChooserViewModel @Inject constructor(args: SavedStateHandle, flags: ChooserServiceFlags) : + ViewModel() { private val mActivityLaunch: ActivityLaunch = requireNotNull(args[ACTIVITY_LAUNCH_KEY]) { @@ -36,7 +38,8 @@ class ChooserViewModel @Inject constructor(args: SavedStateHandle) : ViewModel() } /** The result of reading and validating the inputs provided in savedState. */ - private val status: ValidationResult<ChooserRequest> = readChooserRequest(mActivityLaunch) + private val status: ValidationResult<ChooserRequest> = + readChooserRequest(mActivityLaunch, flags) val chooserRequest: ChooserRequest by lazy { status.getOrThrow() } diff --git a/tests/unit/src/com/android/intentresolver/ChooserRequestParametersTest.kt b/tests/unit/src/com/android/intentresolver/ChooserRequestParametersTest.kt index 90f6cf93..e721b5bb 100644 --- a/tests/unit/src/com/android/intentresolver/ChooserRequestParametersTest.kt +++ b/tests/unit/src/com/android/intentresolver/ChooserRequestParametersTest.kt @@ -29,7 +29,6 @@ import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) class ChooserRequestParametersTest { - @Test fun testChooserActions() { val actionCount = 3 diff --git a/tests/unit/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUiTest.kt b/tests/unit/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUiTest.kt index 083ef180..2a6e09f5 100644 --- a/tests/unit/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUiTest.kt +++ b/tests/unit/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUiTest.kt @@ -18,8 +18,9 @@ package com.android.intentresolver.contentpreview import android.content.Intent import android.net.Uri -import com.android.intentresolver.contentpreview.ChooserContentPreviewUi.ActionFactory +import com.android.intentresolver.ContentTypeHint import com.android.intentresolver.TestPreviewImageLoader +import com.android.intentresolver.contentpreview.ChooserContentPreviewUi.ActionFactory import com.android.intentresolver.mock import com.android.intentresolver.whenever import com.android.intentresolver.widget.ActionRow @@ -62,6 +63,7 @@ class ChooserContentPreviewUiTest { actionFactory, transitionCallback, headlineGenerator, + ContentTypeHint.NONE, ) assertThat(testSubject.preferredContentPreview) .isEqualTo(ContentPreviewType.CONTENT_PREVIEW_TEXT) @@ -81,6 +83,7 @@ class ChooserContentPreviewUiTest { actionFactory, transitionCallback, headlineGenerator, + ContentTypeHint.NONE, ) assertThat(testSubject.preferredContentPreview) .isEqualTo(ContentPreviewType.CONTENT_PREVIEW_FILE) @@ -105,6 +108,7 @@ class ChooserContentPreviewUiTest { actionFactory, transitionCallback, headlineGenerator, + ContentTypeHint.NONE, ) assertThat(testSubject.mContentPreviewUi) .isInstanceOf(FilesPlusTextContentPreviewUi::class.java) @@ -129,6 +133,7 @@ class ChooserContentPreviewUiTest { actionFactory, transitionCallback, headlineGenerator, + ContentTypeHint.NONE, ) assertThat(testSubject.preferredContentPreview) .isEqualTo(ContentPreviewType.CONTENT_PREVIEW_IMAGE) diff --git a/tests/unit/src/com/android/intentresolver/contentpreview/HeadlineGeneratorImplTest.kt b/tests/unit/src/com/android/intentresolver/contentpreview/HeadlineGeneratorImplTest.kt index a65280e5..dbc37b44 100644 --- a/tests/unit/src/com/android/intentresolver/contentpreview/HeadlineGeneratorImplTest.kt +++ b/tests/unit/src/com/android/intentresolver/contentpreview/HeadlineGeneratorImplTest.kt @@ -18,44 +18,73 @@ package com.android.intentresolver.contentpreview import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry +import com.google.common.truth.Truth.assertThat import org.junit.Test import org.junit.runner.RunWith -import com.google.common.truth.Truth.assertThat @RunWith(AndroidJUnit4::class) class HeadlineGeneratorImplTest { - @Test - fun testHeadlineGeneration() { - val generator = HeadlineGeneratorImpl( - InstrumentationRegistry.getInstrumentation().getTargetContext()) - val str = "Some string" - val url = "http://www.google.com" + private val generator = + HeadlineGeneratorImpl(InstrumentationRegistry.getInstrumentation().targetContext) + private val str = "Some string" + private val url = "http://www.google.com" + @Test + fun testTextHeadline() { assertThat(generator.getTextHeadline(str)).isEqualTo("Sharing text") assertThat(generator.getTextHeadline(url)).isEqualTo("Sharing link") + } + @Test + fun testImagesWIthTextHeadline() { assertThat(generator.getImagesWithTextHeadline(str, 1)).isEqualTo("Sharing image with text") assertThat(generator.getImagesWithTextHeadline(url, 1)).isEqualTo("Sharing image with link") - assertThat(generator.getImagesWithTextHeadline(str, 5)).isEqualTo("Sharing 5 images with text") - assertThat(generator.getImagesWithTextHeadline(url, 5)).isEqualTo("Sharing 5 images with link") + assertThat(generator.getImagesWithTextHeadline(str, 5)) + .isEqualTo("Sharing 5 images with text") + assertThat(generator.getImagesWithTextHeadline(url, 5)) + .isEqualTo("Sharing 5 images with link") + } + @Test + fun testVideosWithTextHeadline() { assertThat(generator.getVideosWithTextHeadline(str, 1)).isEqualTo("Sharing video with text") assertThat(generator.getVideosWithTextHeadline(url, 1)).isEqualTo("Sharing video with link") - assertThat(generator.getVideosWithTextHeadline(str, 5)).isEqualTo("Sharing 5 videos with text") - assertThat(generator.getVideosWithTextHeadline(url, 5)).isEqualTo("Sharing 5 videos with link") + assertThat(generator.getVideosWithTextHeadline(str, 5)) + .isEqualTo("Sharing 5 videos with text") + assertThat(generator.getVideosWithTextHeadline(url, 5)) + .isEqualTo("Sharing 5 videos with link") + } + @Test + fun testFilesWithTextHeadline() { assertThat(generator.getFilesWithTextHeadline(str, 1)).isEqualTo("Sharing file with text") assertThat(generator.getFilesWithTextHeadline(url, 1)).isEqualTo("Sharing file with link") - assertThat(generator.getFilesWithTextHeadline(str, 5)).isEqualTo("Sharing 5 files with text") - assertThat(generator.getFilesWithTextHeadline(url, 5)).isEqualTo("Sharing 5 files with link") + assertThat(generator.getFilesWithTextHeadline(str, 5)) + .isEqualTo("Sharing 5 files with text") + assertThat(generator.getFilesWithTextHeadline(url, 5)) + .isEqualTo("Sharing 5 files with link") + } + @Test + fun testImagesHeadline() { assertThat(generator.getImagesHeadline(1)).isEqualTo("Sharing image") assertThat(generator.getImagesHeadline(4)).isEqualTo("Sharing 4 images") + } + @Test + fun testVideosHeadline() { assertThat(generator.getVideosHeadline(1)).isEqualTo("Sharing video") assertThat(generator.getVideosHeadline(4)).isEqualTo("Sharing 4 videos") + } + @Test + fun testFilesHeadline() { assertThat(generator.getFilesHeadline(1)).isEqualTo("Sharing 1 file") assertThat(generator.getFilesHeadline(4)).isEqualTo("Sharing 4 files") } + + @Test + fun testAlbumHeadline() { + assertThat(generator.getAlbumHeadline()).isEqualTo("Sharing album") + } } diff --git a/tests/unit/src/com/android/intentresolver/contentpreview/TextContentPreviewUiTest.kt b/tests/unit/src/com/android/intentresolver/contentpreview/TextContentPreviewUiTest.kt index 35362401..4f200268 100644 --- a/tests/unit/src/com/android/intentresolver/contentpreview/TextContentPreviewUiTest.kt +++ b/tests/unit/src/com/android/intentresolver/contentpreview/TextContentPreviewUiTest.kt @@ -22,6 +22,7 @@ import android.view.ViewGroup import android.widget.TextView import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry +import com.android.intentresolver.ContentTypeHint import com.android.intentresolver.R import com.android.intentresolver.mock import com.android.intentresolver.whenever @@ -38,6 +39,7 @@ import org.junit.runner.RunWith class TextContentPreviewUiTest { private val text = "Shared Text" private val title = "Preview Title" + private val albumHeadline = "Album headline" private val testScope = TestScope(EmptyCoroutineContext + UnconfinedTestDispatcher()) private val actionFactory = object : ChooserContentPreviewUi.ActionFactory { @@ -49,7 +51,10 @@ class TextContentPreviewUiTest { } private val imageLoader = mock<ImageLoader>() private val headlineGenerator = - mock<HeadlineGenerator> { whenever(getTextHeadline(text)).thenReturn(text) } + mock<HeadlineGenerator> { + whenever(getTextHeadline(text)).thenReturn(text) + whenever(getAlbumHeadline()).thenReturn(albumHeadline) + } private val context get() = InstrumentationRegistry.getInstrumentation().context @@ -63,6 +68,7 @@ class TextContentPreviewUiTest { actionFactory, imageLoader, headlineGenerator, + ContentTypeHint.NONE, ) @Test @@ -105,4 +111,35 @@ class TextContentPreviewUiTest { assertThat(headlineView).isNotNull() assertThat(headlineView?.text).isEqualTo(text) } + + @Test + fun test_display_albumHeadlineOverride() { + val layoutInflater = LayoutInflater.from(context) + val gridLayout = layoutInflater.inflate(R.layout.chooser_grid, null, false) as ViewGroup + + val albumSubject = + TextContentPreviewUi( + testScope, + text, + title, + /*previewThumbnail=*/ null, + actionFactory, + imageLoader, + headlineGenerator, + ContentTypeHint.ALBUM, + ) + + val previewView = + albumSubject.display( + context.resources, + layoutInflater, + gridLayout, + /*headlineViewParent=*/ null + ) + + assertThat(previewView).isNotNull() + val headlineView = previewView?.findViewById<TextView>(R.id.headline) + assertThat(headlineView).isNotNull() + assertThat(headlineView?.text).isEqualTo(albumHeadline) + } } diff --git a/tests/unit/src/com/android/intentresolver/v2/ui/viewmodel/ChooserRequestTest.kt b/tests/unit/src/com/android/intentresolver/v2/ui/viewmodel/ChooserRequestTest.kt index 9ac24c64..831d09bf 100644 --- a/tests/unit/src/com/android/intentresolver/v2/ui/viewmodel/ChooserRequestTest.kt +++ b/tests/unit/src/com/android/intentresolver/v2/ui/viewmodel/ChooserRequestTest.kt @@ -28,8 +28,10 @@ import android.platform.test.annotations.RequiresFlagsDisabled import android.platform.test.annotations.RequiresFlagsEnabled import android.platform.test.flag.junit.CheckFlagsRule import android.platform.test.flag.junit.DeviceFlagsValueProvider +import android.service.chooser.FeatureFlagsImpl import androidx.core.net.toUri import androidx.core.os.bundleOf +import com.android.intentresolver.ContentTypeHint import com.android.intentresolver.v2.ui.model.ActivityLaunch import com.android.intentresolver.v2.ui.model.ChooserRequest import com.android.intentresolver.v2.validation.RequiredValueMissing @@ -41,6 +43,7 @@ import org.junit.Test // TODO: replace with the new API constant, Intent#EXTRA_CHOOSER_ADDITIONAL_CONTENT_URI private const val EXTRA_CHOOSER_ADDITIONAL_CONTENT_URI = "android.intent.extra.CHOOSER_ADDITIONAL_CONTENT_URI" + // TODO: replace with the new API constant, Intent#EXTRA_CHOOSER_FOCUSED_ITEM_POSITION private const val EXTRA_CHOOSER_FOCUSED_ITEM_POSITION = "android.intent.extra.CHOOSER_FOCUSED_ITEM_POSITION" @@ -63,10 +66,12 @@ private fun createLaunch( class ChooserRequestTest { @get:Rule val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() + private val flags = FeatureFlagsImpl() + @Test fun missingIntent() { val launch = createLaunch(targetIntent = null) - val result = readChooserRequest(launch) + val result = readChooserRequest(launch, flags) assertThat(result).value().isNull() assertThat(result) @@ -80,7 +85,7 @@ class ChooserRequestTest { val launch = createLaunch(targetIntent = Intent(ACTION_SEND), referrer) launch.intent.putExtras(bundleOf(EXTRA_REFERRER to referrer)) - val result = readChooserRequest(launch) + val result = readChooserRequest(launch, flags) val fillIn = result.value?.getReferrerFillInIntent() assertThat(fillIn?.hasExtra(EXTRA_REFERRER)).isTrue() @@ -94,7 +99,7 @@ class ChooserRequestTest { val launch = createLaunch(targetIntent = intent, referrer = referrer) - val result = readChooserRequest(launch) + val result = readChooserRequest(launch, flags) assertThat(result.value?.referrerPackage).isNull() } @@ -106,7 +111,7 @@ class ChooserRequestTest { launch.intent.putExtras(bundleOf(EXTRA_REFERRER to referrer)) - val result = readChooserRequest(launch) + val result = readChooserRequest(launch, flags) assertThat(result.value?.referrerPackage).isEqualTo(referrer.authority) } @@ -116,7 +121,7 @@ class ChooserRequestTest { val intent1 = Intent(ACTION_SEND) val intent2 = Intent(ACTION_SEND_MULTIPLE) val launch = createLaunch(targetIntent = intent1, additionalIntents = listOf(intent2)) - val result = readChooserRequest(launch) + val result = readChooserRequest(launch, flags) assertThat(result.value?.payloadIntents).containsExactly(intent1, intent2) } @@ -125,7 +130,7 @@ class ChooserRequestTest { fun testRequest_withOnlyRequiredValues() { val intent = Intent().putExtras(bundleOf(EXTRA_INTENT to Intent(ACTION_SEND))) val launch = createLaunch(targetIntent = intent) - val result = readChooserRequest(launch) + val result = readChooserRequest(launch, flags) assertThat(result).value().isNotNull() val value: ChooserRequest = result.getOrThrow() @@ -143,7 +148,7 @@ class ChooserRequestTest { intent.putExtra(EXTRA_CHOOSER_ADDITIONAL_CONTENT_URI, uri) intent.putExtra(EXTRA_CHOOSER_FOCUSED_ITEM_POSITION, position) } - val result = readChooserRequest(launch) + val result = readChooserRequest(launch, flags) assertThat(result).value().isNotNull() val value: ChooserRequest = result.getOrThrow() @@ -162,7 +167,7 @@ class ChooserRequestTest { intent.putExtra(EXTRA_CHOOSER_ADDITIONAL_CONTENT_URI, uri) intent.putExtra(EXTRA_CHOOSER_FOCUSED_ITEM_POSITION, position) } - val result = readChooserRequest(launch) + val result = readChooserRequest(launch, flags) assertThat(result).value().isNotNull() val value: ChooserRequest = result.getOrThrow() @@ -179,7 +184,7 @@ class ChooserRequestTest { intent.putExtra(EXTRA_CHOOSER_ADDITIONAL_CONTENT_URI, "content://org.pkg/path") intent.putExtra(EXTRA_CHOOSER_FOCUSED_ITEM_POSITION, "1") } - val result = readChooserRequest(launch) + val result = readChooserRequest(launch, flags) assertThat(result).value().isNotNull() val value: ChooserRequest = result.getOrThrow() @@ -191,7 +196,7 @@ class ChooserRequestTest { @RequiresFlagsEnabled(android.service.chooser.Flags.FLAG_CHOOSER_PAYLOAD_TOGGLING) fun testRequest_actionSendWithoutAdditionalContentUri() { val launch = createLaunch(targetIntent = Intent(ACTION_SEND)) - val result = readChooserRequest(launch) + val result = readChooserRequest(launch, flags) assertThat(result).value().isNotNull() val value: ChooserRequest = result.getOrThrow() @@ -209,7 +214,7 @@ class ChooserRequestTest { intent.putExtra(EXTRA_CHOOSER_ADDITIONAL_CONTENT_URI, uri) intent.putExtra(EXTRA_CHOOSER_FOCUSED_ITEM_POSITION, position) } - val result = readChooserRequest(launch) + val result = readChooserRequest(launch, flags) assertThat(result).value().isNotNull() val value: ChooserRequest = result.getOrThrow() @@ -217,4 +222,20 @@ class ChooserRequestTest { assertThat(value.focusedItemPosition).isEqualTo(0) assertThat(result).findings().isEmpty() } + + @Test + @RequiresFlagsEnabled(android.service.chooser.Flags.FLAG_CHOOSER_ALBUM_TEXT) + fun testAlbumType() { + val launch = createLaunch(Intent(ACTION_SEND)) + launch.intent.putExtra( + Intent.EXTRA_CHOOSER_CONTENT_TYPE_HINT, + Intent.CHOOSER_CONTENT_TYPE_ALBUM + ) + + val result = readChooserRequest(launch, flags) + + val value: ChooserRequest = result.getOrThrow() + assertThat(value.contentTypeHint).isEqualTo(ContentTypeHint.ALBUM) + assertThat(result).findings().isEmpty() + } } |