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