1 /* <lambda>null2 * 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.ClipDescription 20 import android.content.ContentInterface 21 import android.content.Intent 22 import android.graphics.Bitmap 23 import android.net.Uri 24 import com.android.intentresolver.ImageLoader 25 import com.android.intentresolver.TestFeatureFlagRepository 26 import com.android.intentresolver.contentpreview.ChooserContentPreviewUi.ActionFactory 27 import com.android.intentresolver.flags.Flags 28 import com.android.intentresolver.mock 29 import com.android.intentresolver.whenever 30 import com.android.intentresolver.widget.ActionRow 31 import com.android.intentresolver.widget.ImagePreviewView 32 import com.google.common.truth.Truth.assertThat 33 import org.junit.Test 34 import org.mockito.Mockito.never 35 import org.mockito.Mockito.times 36 import org.mockito.Mockito.verify 37 import java.util.function.Consumer 38 39 private const val PROVIDER_NAME = "org.pkg.app" 40 class ChooserContentPreviewUiTest { 41 private val contentResolver = mock<ContentInterface>() 42 private val imageClassifier = ChooserContentPreviewUi.ImageMimeTypeClassifier { mimeType -> 43 mimeType != null && ClipDescription.compareMimeTypes(mimeType, "image/*") 44 } 45 private val imageLoader = object : ImageLoader { 46 override fun loadImage(uri: Uri, callback: Consumer<Bitmap?>) { 47 callback.accept(null) 48 } 49 override fun prePopulate(uris: List<Uri>) = Unit 50 override suspend fun invoke(uri: Uri): Bitmap? = null 51 } 52 private val actionFactory = object : ActionFactory { 53 override fun createCopyButton() = ActionRow.Action(label = "Copy", icon = null) {} 54 override fun createEditButton(): ActionRow.Action? = null 55 override fun createNearbyButton(): ActionRow.Action? = null 56 override fun createCustomActions(): List<ActionRow.Action> = emptyList() 57 override fun getModifyShareAction(): Runnable? = null 58 override fun getExcludeSharedTextAction(): Consumer<Boolean> = Consumer<Boolean> {} 59 } 60 private val transitionCallback = mock<ImagePreviewView.TransitionElementStatusCallback>() 61 private val featureFlagRepository = TestFeatureFlagRepository( 62 mapOf( 63 Flags.SHARESHEET_SCROLLABLE_IMAGE_PREVIEW to true 64 ) 65 ) 66 67 @Test 68 fun test_ChooserContentPreview_non_send_intent_action_to_text_preview() { 69 val targetIntent = Intent(Intent.ACTION_VIEW) 70 val testSubject = ChooserContentPreviewUi( 71 targetIntent, 72 contentResolver, 73 imageClassifier, 74 imageLoader, 75 actionFactory, 76 transitionCallback, 77 featureFlagRepository 78 ) 79 assertThat(testSubject.preferredContentPreview) 80 .isEqualTo(ContentPreviewType.CONTENT_PREVIEW_TEXT) 81 verify(transitionCallback, times(1)).onAllTransitionElementsReady() 82 } 83 84 @Test 85 fun test_ChooserContentPreview_text_mime_type_to_text_preview() { 86 val targetIntent = Intent(Intent.ACTION_SEND).apply { 87 type = "text/plain" 88 putExtra(Intent.EXTRA_TEXT, "Text Extra") 89 } 90 val testSubject = ChooserContentPreviewUi( 91 targetIntent, 92 contentResolver, 93 imageClassifier, 94 imageLoader, 95 actionFactory, 96 transitionCallback, 97 featureFlagRepository 98 ) 99 assertThat(testSubject.preferredContentPreview) 100 .isEqualTo(ContentPreviewType.CONTENT_PREVIEW_TEXT) 101 verify(transitionCallback, times(1)).onAllTransitionElementsReady() 102 } 103 104 @Test 105 fun test_ChooserContentPreview_single_image_uri_to_image_preview() { 106 val uri = Uri.parse("content://$PROVIDER_NAME/test.png") 107 val targetIntent = Intent(Intent.ACTION_SEND).apply { 108 putExtra(Intent.EXTRA_STREAM, uri) 109 } 110 whenever(contentResolver.getType(uri)).thenReturn("image/png") 111 val testSubject = ChooserContentPreviewUi( 112 targetIntent, 113 contentResolver, 114 imageClassifier, 115 imageLoader, 116 actionFactory, 117 transitionCallback, 118 featureFlagRepository 119 ) 120 assertThat(testSubject.preferredContentPreview) 121 .isEqualTo(ContentPreviewType.CONTENT_PREVIEW_IMAGE) 122 verify(transitionCallback, never()).onAllTransitionElementsReady() 123 } 124 125 @Test 126 fun test_ChooserContentPreview_single_non_image_uri_to_file_preview() { 127 val uri = Uri.parse("content://$PROVIDER_NAME/test.pdf") 128 val targetIntent = Intent(Intent.ACTION_SEND).apply { 129 putExtra(Intent.EXTRA_STREAM, uri) 130 } 131 whenever(contentResolver.getType(uri)).thenReturn("application/pdf") 132 val testSubject = ChooserContentPreviewUi( 133 targetIntent, 134 contentResolver, 135 imageClassifier, 136 imageLoader, 137 actionFactory, 138 transitionCallback, 139 featureFlagRepository 140 ) 141 assertThat(testSubject.preferredContentPreview) 142 .isEqualTo(ContentPreviewType.CONTENT_PREVIEW_FILE) 143 verify(transitionCallback, times(1)).onAllTransitionElementsReady() 144 } 145 146 @Test 147 fun test_ChooserContentPreview_multiple_image_uri_to_image_preview() { 148 val uri1 = Uri.parse("content://$PROVIDER_NAME/test.png") 149 val uri2 = Uri.parse("content://$PROVIDER_NAME/test.jpg") 150 val targetIntent = Intent(Intent.ACTION_SEND_MULTIPLE).apply { 151 putExtra( 152 Intent.EXTRA_STREAM, 153 ArrayList<Uri>().apply { 154 add(uri1) 155 add(uri2) 156 } 157 ) 158 } 159 whenever(contentResolver.getType(uri1)).thenReturn("image/png") 160 whenever(contentResolver.getType(uri2)).thenReturn("image/jpeg") 161 val testSubject = ChooserContentPreviewUi( 162 targetIntent, 163 contentResolver, 164 imageClassifier, 165 imageLoader, 166 actionFactory, 167 transitionCallback, 168 featureFlagRepository 169 ) 170 assertThat(testSubject.preferredContentPreview) 171 .isEqualTo(ContentPreviewType.CONTENT_PREVIEW_IMAGE) 172 verify(transitionCallback, never()).onAllTransitionElementsReady() 173 } 174 175 @Test 176 fun test_ChooserContentPreview_some_non_image_uri_to_file_preview() { 177 val uri1 = Uri.parse("content://$PROVIDER_NAME/test.png") 178 val uri2 = Uri.parse("content://$PROVIDER_NAME/test.pdf") 179 val targetIntent = Intent(Intent.ACTION_SEND_MULTIPLE).apply { 180 putExtra( 181 Intent.EXTRA_STREAM, 182 ArrayList<Uri>().apply { 183 add(uri1) 184 add(uri2) 185 } 186 ) 187 } 188 whenever(contentResolver.getType(uri1)).thenReturn("image/png") 189 whenever(contentResolver.getType(uri2)).thenReturn("application/pdf") 190 val testSubject = ChooserContentPreviewUi( 191 targetIntent, 192 contentResolver, 193 imageClassifier, 194 imageLoader, 195 actionFactory, 196 transitionCallback, 197 featureFlagRepository 198 ) 199 assertThat(testSubject.preferredContentPreview) 200 .isEqualTo(ContentPreviewType.CONTENT_PREVIEW_FILE) 201 verify(transitionCallback, times(1)).onAllTransitionElementsReady() 202 } 203 } 204