1 /* <lambda>null2 * Copyright (C) 2024 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.ui 18 19 import android.app.PendingIntent 20 import android.compat.testing.PlatformCompatChangeRule 21 import android.content.ComponentName 22 import android.content.Intent 23 import android.os.Process 24 import android.service.chooser.ChooserResult 25 import android.service.chooser.Flags 26 import androidx.test.platform.app.InstrumentationRegistry 27 import com.android.intentresolver.inject.FakeChooserServiceFlags 28 import com.android.intentresolver.ui.model.ShareAction 29 import com.google.common.truth.Truth.assertThat 30 import com.google.common.truth.Truth.assertWithMessage 31 import kotlinx.coroutines.CompletableDeferred 32 import kotlinx.coroutines.ExperimentalCoroutinesApi 33 import kotlinx.coroutines.test.UnconfinedTestDispatcher 34 import kotlinx.coroutines.test.runCurrent 35 import kotlinx.coroutines.test.runTest 36 import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges 37 import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges 38 import org.junit.Rule 39 import org.junit.Test 40 import org.junit.rules.TestRule 41 42 @OptIn(ExperimentalCoroutinesApi::class) 43 class ShareResultSenderImplTest { 44 45 private val context = InstrumentationRegistry.getInstrumentation().context 46 47 @get:Rule val compatChangeRule: TestRule = PlatformCompatChangeRule() 48 49 val flags = FakeChooserServiceFlags() 50 51 @OptIn(ExperimentalCoroutinesApi::class) 52 @EnableCompatChanges(ChooserResult.SEND_CHOOSER_RESULT) 53 @Test 54 fun onComponentSelected_chooserResultEnabled() = runTest { 55 val pi = PendingIntent.getBroadcast(context, 0, Intent(), PendingIntent.FLAG_IMMUTABLE) 56 val deferred = CompletableDeferred<Intent>() 57 val intentDispatcher = IntentSenderDispatcher { _, intent -> deferred.complete(intent) } 58 59 flags.setFlag(Flags.FLAG_ENABLE_CHOOSER_RESULT, true) 60 61 val resultSender = 62 ShareResultSenderImpl( 63 flags = flags, 64 scope = this, 65 backgroundDispatcher = UnconfinedTestDispatcher(testScheduler), 66 callerUid = Process.myUid(), 67 resultSender = pi.intentSender, 68 intentDispatcher = intentDispatcher 69 ) 70 71 resultSender.onComponentSelected(ComponentName("example.com", "Foo"), true) 72 runCurrent() 73 74 val intentReceived = deferred.await() 75 val chooserResult = 76 intentReceived.getParcelableExtra( 77 Intent.EXTRA_CHOOSER_RESULT, 78 ChooserResult::class.java 79 ) 80 assertThat(chooserResult).isNotNull() 81 assertThat(chooserResult?.type).isEqualTo(ChooserResult.CHOOSER_RESULT_SELECTED_COMPONENT) 82 assertThat(chooserResult?.selectedComponent).isEqualTo(ComponentName("example.com", "Foo")) 83 assertThat(chooserResult?.isShortcut).isTrue() 84 } 85 86 @DisableCompatChanges(ChooserResult.SEND_CHOOSER_RESULT) 87 @Test 88 fun onComponentSelected_chooserResultDisabled() = runTest { 89 val pi = PendingIntent.getBroadcast(context, 0, Intent(), PendingIntent.FLAG_IMMUTABLE) 90 val deferred = CompletableDeferred<Intent>() 91 val intentDispatcher = IntentSenderDispatcher { _, intent -> deferred.complete(intent) } 92 93 flags.setFlag(Flags.FLAG_ENABLE_CHOOSER_RESULT, true) 94 95 val resultSender = 96 ShareResultSenderImpl( 97 flags = flags, 98 scope = this, 99 backgroundDispatcher = UnconfinedTestDispatcher(testScheduler), 100 callerUid = Process.myUid(), 101 resultSender = pi.intentSender, 102 intentDispatcher = intentDispatcher 103 ) 104 105 resultSender.onComponentSelected(ComponentName("example.com", "Foo"), true) 106 runCurrent() 107 108 val intentReceived = deferred.await() 109 val componentName = 110 intentReceived.getParcelableExtra( 111 Intent.EXTRA_CHOSEN_COMPONENT, 112 ComponentName::class.java 113 ) 114 115 assertWithMessage("EXTRA_CHOSEN_COMPONENT from received intent") 116 .that(componentName) 117 .isEqualTo(ComponentName("example.com", "Foo")) 118 119 assertWithMessage("received intent has EXTRA_CHOOSER_RESULT") 120 .that(intentReceived.hasExtra(Intent.EXTRA_CHOOSER_RESULT)) 121 .isFalse() 122 } 123 124 @EnableCompatChanges(ChooserResult.SEND_CHOOSER_RESULT) 125 @Test 126 fun onActionSelected_chooserResultEnabled() = runTest { 127 val pi = PendingIntent.getBroadcast(context, 0, Intent(), PendingIntent.FLAG_IMMUTABLE) 128 val deferred = CompletableDeferred<Intent>() 129 val intentDispatcher = IntentSenderDispatcher { _, intent -> deferred.complete(intent) } 130 131 flags.setFlag(Flags.FLAG_ENABLE_CHOOSER_RESULT, true) 132 133 val resultSender = 134 ShareResultSenderImpl( 135 flags = flags, 136 scope = this, 137 backgroundDispatcher = UnconfinedTestDispatcher(testScheduler), 138 callerUid = Process.myUid(), 139 resultSender = pi.intentSender, 140 intentDispatcher = intentDispatcher 141 ) 142 143 resultSender.onActionSelected(ShareAction.SYSTEM_COPY) 144 runCurrent() 145 146 val intentReceived = deferred.await() 147 val chosenComponent = 148 intentReceived.getParcelableExtra( 149 Intent.EXTRA_CHOSEN_COMPONENT, 150 ChooserResult::class.java 151 ) 152 assertThat(chosenComponent).isNull() 153 154 val chooserResult = 155 intentReceived.getParcelableExtra( 156 Intent.EXTRA_CHOOSER_RESULT, 157 ChooserResult::class.java 158 ) 159 assertThat(chooserResult).isNotNull() 160 assertThat(chooserResult?.type).isEqualTo(ChooserResult.CHOOSER_RESULT_COPY) 161 assertThat(chooserResult?.selectedComponent).isNull() 162 assertThat(chooserResult?.isShortcut).isFalse() 163 } 164 165 @DisableCompatChanges(ChooserResult.SEND_CHOOSER_RESULT) 166 @Test 167 fun onActionSelected_chooserResultDisabled() = runTest { 168 val pi = PendingIntent.getBroadcast(context, 0, Intent(), PendingIntent.FLAG_IMMUTABLE) 169 val deferred = CompletableDeferred<Intent>() 170 val intentDispatcher = IntentSenderDispatcher { _, intent -> deferred.complete(intent) } 171 172 flags.setFlag(Flags.FLAG_ENABLE_CHOOSER_RESULT, true) 173 174 val resultSender = 175 ShareResultSenderImpl( 176 flags = flags, 177 scope = this, 178 backgroundDispatcher = UnconfinedTestDispatcher(testScheduler), 179 callerUid = Process.myUid(), 180 resultSender = pi.intentSender, 181 intentDispatcher = intentDispatcher 182 ) 183 184 resultSender.onActionSelected(ShareAction.SYSTEM_COPY) 185 runCurrent() 186 187 // No result should have been sent, this should never complete 188 assertWithMessage("deferred result isComplete").that(deferred.isCompleted).isFalse() 189 } 190 } 191