1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.intentresolver.contentpreview
18 
19 import android.content.Intent
20 import android.net.Uri
21 import android.platform.test.flag.junit.CheckFlagsRule
22 import android.platform.test.flag.junit.DeviceFlagsValueProvider
23 import com.android.intentresolver.ContentTypeHint
24 import com.android.intentresolver.FakeImageLoader
25 import com.android.intentresolver.contentpreview.ChooserContentPreviewUi.ActionFactory
26 import com.android.intentresolver.data.model.ChooserRequest
27 import com.android.intentresolver.widget.ActionRow
28 import com.android.intentresolver.widget.ImagePreviewView
29 import com.google.common.truth.Truth.assertThat
30 import java.util.function.Consumer
31 import kotlin.coroutines.EmptyCoroutineContext
32 import kotlinx.coroutines.flow.MutableSharedFlow
33 import kotlinx.coroutines.test.TestScope
34 import kotlinx.coroutines.test.UnconfinedTestDispatcher
35 import org.junit.Rule
36 import org.junit.Test
37 import org.mockito.Mockito.never
38 import org.mockito.Mockito.times
39 import org.mockito.Mockito.verify
40 import org.mockito.kotlin.mock
41 import org.mockito.kotlin.whenever
42 
43 class ChooserContentPreviewUiTest {
44     private val testScope = TestScope(EmptyCoroutineContext + UnconfinedTestDispatcher())
45     private val previewData = mock<PreviewDataProvider>()
46     private val headlineGenerator = mock<HeadlineGenerator>()
47     private val imageLoader = FakeImageLoader(emptyMap())
48     private val testMetadataText: CharSequence = "Test metadata text"
49     private val actionFactory =
50         object : ActionFactory {
getCopyButtonRunnablenull51             override fun getCopyButtonRunnable(): Runnable? = null
52 
53             override fun getEditButtonRunnable(): Runnable? = null
54 
55             override fun createCustomActions(): List<ActionRow.Action> = emptyList()
56 
57             override fun getModifyShareAction(): ActionRow.Action? = null
58 
59             override fun getExcludeSharedTextAction(): Consumer<Boolean> = Consumer<Boolean> {}
60         }
61     private val transitionCallback = mock<ImagePreviewView.TransitionElementStatusCallback>()
62     @get:Rule val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
63 
createContentPreviewUinull64     private fun createContentPreviewUi(action: String, sharedText: CharSequence? = null) =
65         ChooserContentPreviewUi(
66             testScope,
67             previewData,
68             ChooserRequest(
69                 targetIntent = Intent(action),
70                 sharedText = sharedText,
71                 launchedFromPackage = "org.pkg",
72             ),
73             imageLoader,
74             actionFactory,
75             { null },
76             transitionCallback,
77             headlineGenerator,
78             ContentTypeHint.NONE,
79             testMetadataText,
80         )
81 
82     @Test
test_textPreviewType_useTextPreviewUinull83     fun test_textPreviewType_useTextPreviewUi() {
84         whenever(previewData.previewType).thenReturn(ContentPreviewType.CONTENT_PREVIEW_TEXT)
85         val testSubject = createContentPreviewUi(action = Intent.ACTION_VIEW)
86 
87         assertThat(testSubject.preferredContentPreview)
88             .isEqualTo(ContentPreviewType.CONTENT_PREVIEW_TEXT)
89         assertThat(testSubject.mContentPreviewUi).isInstanceOf(TextContentPreviewUi::class.java)
90         verify(transitionCallback, times(1)).onAllTransitionElementsReady()
91     }
92 
93     @Test
test_filePreviewType_useFilePreviewUinull94     fun test_filePreviewType_useFilePreviewUi() {
95         whenever(previewData.previewType).thenReturn(ContentPreviewType.CONTENT_PREVIEW_FILE)
96         val testSubject = createContentPreviewUi(action = Intent.ACTION_SEND)
97         assertThat(testSubject.preferredContentPreview)
98             .isEqualTo(ContentPreviewType.CONTENT_PREVIEW_FILE)
99         assertThat(testSubject.mContentPreviewUi).isInstanceOf(FileContentPreviewUi::class.java)
100         verify(transitionCallback, times(1)).onAllTransitionElementsReady()
101     }
102 
103     @Test
test_imagePreviewTypeWithText_useFilePlusTextPreviewUinull104     fun test_imagePreviewTypeWithText_useFilePlusTextPreviewUi() {
105         val uri = Uri.parse("content://org.pkg.app/img.png")
106         whenever(previewData.previewType).thenReturn(ContentPreviewType.CONTENT_PREVIEW_IMAGE)
107         whenever(previewData.uriCount).thenReturn(2)
108         whenever(previewData.firstFileInfo)
109             .thenReturn(FileInfo.Builder(uri).withPreviewUri(uri).withMimeType("image/png").build())
110         whenever(previewData.imagePreviewFileInfoFlow).thenReturn(MutableSharedFlow())
111         val testSubject =
112             createContentPreviewUi(action = Intent.ACTION_SEND, sharedText = "Shared text")
113         assertThat(testSubject.mContentPreviewUi)
114             .isInstanceOf(FilesPlusTextContentPreviewUi::class.java)
115         verify(previewData, times(1)).imagePreviewFileInfoFlow
116         verify(transitionCallback, times(1)).onAllTransitionElementsReady()
117     }
118 
119     @Test
test_imagePreviewTypeWithoutText_useImagePreviewUinull120     fun test_imagePreviewTypeWithoutText_useImagePreviewUi() {
121         val uri = Uri.parse("content://org.pkg.app/img.png")
122         whenever(previewData.previewType).thenReturn(ContentPreviewType.CONTENT_PREVIEW_IMAGE)
123         whenever(previewData.uriCount).thenReturn(2)
124         whenever(previewData.firstFileInfo)
125             .thenReturn(FileInfo.Builder(uri).withPreviewUri(uri).withMimeType("image/png").build())
126         whenever(previewData.imagePreviewFileInfoFlow).thenReturn(MutableSharedFlow())
127         val testSubject = createContentPreviewUi(action = Intent.ACTION_SEND)
128         assertThat(testSubject.preferredContentPreview)
129             .isEqualTo(ContentPreviewType.CONTENT_PREVIEW_IMAGE)
130         assertThat(testSubject.mContentPreviewUi).isInstanceOf(UnifiedContentPreviewUi::class.java)
131         verify(previewData, times(1)).imagePreviewFileInfoFlow
132         verify(transitionCallback, never()).onAllTransitionElementsReady()
133     }
134 
135     @Test
test_imagePayloadSelectionTypeWithEnabledFlag_usePayloadSelectionPreviewUinull136     fun test_imagePayloadSelectionTypeWithEnabledFlag_usePayloadSelectionPreviewUi() {
137         // Event if we returned wrong type due to a bug, we should not use payload selection UI
138         val uri = Uri.parse("content://org.pkg.app/img.png")
139         whenever(previewData.previewType)
140             .thenReturn(ContentPreviewType.CONTENT_PREVIEW_PAYLOAD_SELECTION)
141         whenever(previewData.uriCount).thenReturn(2)
142         whenever(previewData.firstFileInfo)
143             .thenReturn(FileInfo.Builder(uri).withPreviewUri(uri).withMimeType("image/png").build())
144         whenever(previewData.imagePreviewFileInfoFlow).thenReturn(MutableSharedFlow())
145         val testSubject = createContentPreviewUi(action = Intent.ACTION_SEND)
146         assertThat(testSubject.mContentPreviewUi)
147             .isInstanceOf(ShareouselContentPreviewUi::class.java)
148         assertThat(testSubject.preferredContentPreview)
149             .isEqualTo(ContentPreviewType.CONTENT_PREVIEW_PAYLOAD_SELECTION)
150     }
151 }
152