1 package com.android.systemui.mediaprojection.appselector
2 
3 import android.content.ComponentName
4 import android.os.UserHandle
5 import android.testing.AndroidTestingRunner
6 import androidx.test.filters.SmallTest
7 import com.android.systemui.SysuiTestCase
8 import com.android.systemui.mediaprojection.appselector.data.RecentTask
9 import com.android.systemui.mediaprojection.appselector.data.RecentTaskListProvider
10 import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDevicePolicyResolver
11 import com.android.systemui.util.mockito.any
12 import com.android.systemui.util.mockito.mock
13 import com.android.systemui.util.mockito.whenever
14 import kotlinx.coroutines.CoroutineScope
15 import kotlinx.coroutines.Dispatchers
16 import org.junit.Before
17 import org.junit.Test
18 import org.junit.runner.RunWith
19 import org.mockito.Mockito.verify
20 
21 @RunWith(AndroidTestingRunner::class)
22 @SmallTest
23 class MediaProjectionAppSelectorControllerTest : SysuiTestCase() {
24 
25     private val taskListProvider = TestRecentTaskListProvider()
26     private val scope = CoroutineScope(Dispatchers.Unconfined)
27     private val appSelectorComponentName = ComponentName("com.test", "AppSelector")
28     private val callerPackageName = "com.test.caller"
29     private val callerComponentName = ComponentName(callerPackageName, "Caller")
30 
31     private val personalUserHandle = UserHandle.of(123)
32     private val workUserHandle = UserHandle.of(456)
33 
34     private val view: MediaProjectionAppSelectorView = mock()
35     private val policyResolver: ScreenCaptureDevicePolicyResolver = mock()
36 
37     private val controller =
38         MediaProjectionAppSelectorController(
39             taskListProvider,
40             view,
41             policyResolver,
42             personalUserHandle,
43             scope,
44             appSelectorComponentName,
45             callerPackageName
46         )
47 
48     @Before
49     fun setup() {
50         givenCaptureAllowed(isAllow = true)
51     }
52 
53     @Test
54     fun initNoRecentTasks_bindsEmptyList() {
55         taskListProvider.tasks = emptyList()
56 
57         controller.init()
58 
59         verify(view).bind(emptyList())
60     }
61 
62     @Test
63     fun initOneRecentTask_bindsList() {
64         taskListProvider.tasks = listOf(createRecentTask(taskId = 1))
65 
66         controller.init()
67 
68         verify(view).bind(listOf(createRecentTask(taskId = 1)))
69     }
70 
71     @Test
72     fun initMultipleRecentTasksWithoutAppSelectorTask_bindsListInTheSameOrder() {
73         val tasks =
74             listOf(
75                 createRecentTask(taskId = 1),
76                 createRecentTask(taskId = 2),
77                 createRecentTask(taskId = 3),
78             )
79         taskListProvider.tasks = tasks
80 
81         controller.init()
82 
83         verify(view)
84             .bind(
85                 listOf(
86                     createRecentTask(taskId = 1),
87                     createRecentTask(taskId = 2),
88                     createRecentTask(taskId = 3),
89                 )
90             )
91     }
92 
93     @Test
94     fun initRecentTasksWithAppSelectorTasks_removeAppSelector() {
95         val tasks =
96             listOf(
97                 createRecentTask(taskId = 1),
98                 createRecentTask(taskId = 2, topActivityComponent = appSelectorComponentName),
99                 createRecentTask(taskId = 3),
100                 createRecentTask(taskId = 4),
101             )
102         taskListProvider.tasks = tasks
103 
104         controller.init()
105 
106         verify(view)
107             .bind(
108                 listOf(
109                     createRecentTask(taskId = 1),
110                     createRecentTask(taskId = 3),
111                     createRecentTask(taskId = 4),
112                 )
113             )
114     }
115 
116     @Test
117     fun initRecentTasksWithAppSelectorTasks_bindsCallerTasksAtTheEnd() {
118         val tasks =
119             listOf(
120                 createRecentTask(taskId = 1),
121                 createRecentTask(taskId = 2, topActivityComponent = callerComponentName),
122                 createRecentTask(taskId = 3),
123                 createRecentTask(taskId = 4),
124             )
125         taskListProvider.tasks = tasks
126 
127         controller.init()
128 
129         verify(view)
130             .bind(
131                 listOf(
132                     createRecentTask(taskId = 1),
133                     createRecentTask(taskId = 3),
134                     createRecentTask(taskId = 4),
135                     createRecentTask(taskId = 2, topActivityComponent = callerComponentName),
136                 )
137             )
138     }
139 
140     @Test
141     fun initRecentTasksWithAppSelectorTasks_withEnterprisePolicies_bindsAllTasks() {
142         val tasks =
143             listOf(
144                 createRecentTask(taskId = 1, userId = personalUserHandle.identifier),
145                 createRecentTask(taskId = 2, userId = workUserHandle.identifier),
146                 createRecentTask(taskId = 3, userId = personalUserHandle.identifier),
147                 createRecentTask(taskId = 4, userId = workUserHandle.identifier),
148                 createRecentTask(taskId = 5, userId = personalUserHandle.identifier),
149             )
150         taskListProvider.tasks = tasks
151 
152         controller.init()
153 
154         verify(view)
155             .bind(
156                 listOf(
157                     createRecentTask(taskId = 1, userId = personalUserHandle.identifier),
158                     createRecentTask(taskId = 2, userId = workUserHandle.identifier),
159                     createRecentTask(taskId = 3, userId = personalUserHandle.identifier),
160                     createRecentTask(taskId = 4, userId = workUserHandle.identifier),
161                     createRecentTask(taskId = 5, userId = personalUserHandle.identifier),
162                 )
163             )
164     }
165 
166     @Test
167     fun initRecentTasksWithAppSelectorTasks_withEnterprisePolicies_blocksAllTasks() {
168         val tasks =
169             listOf(
170                 createRecentTask(taskId = 1, userId = personalUserHandle.identifier),
171                 createRecentTask(taskId = 2, userId = workUserHandle.identifier),
172                 createRecentTask(taskId = 3, userId = personalUserHandle.identifier),
173                 createRecentTask(taskId = 4, userId = workUserHandle.identifier),
174                 createRecentTask(taskId = 5, userId = personalUserHandle.identifier),
175             )
176         taskListProvider.tasks = tasks
177 
178         givenCaptureAllowed(isAllow = false)
179         controller.init()
180 
181         verify(view).bind(emptyList())
182     }
183 
184     private fun givenCaptureAllowed(isAllow: Boolean) {
185         whenever(policyResolver.isScreenCaptureAllowed(any(), any())).thenReturn(isAllow)
186     }
187 
188     private fun createRecentTask(
189         taskId: Int,
190         topActivityComponent: ComponentName? = null,
191         userId: Int = personalUserHandle.identifier
192     ): RecentTask {
193         return RecentTask(
194             taskId = taskId,
195             topActivityComponent = topActivityComponent,
196             baseIntentComponent = ComponentName("com", "Test"),
197             userId = userId,
198             colorBackground = 0
199         )
200     }
201 
202     private class TestRecentTaskListProvider : RecentTaskListProvider {
203 
204         var tasks: List<RecentTask> = emptyList()
205 
206         override suspend fun loadRecentTasks(): List<RecentTask> = tasks
207     }
208 }
209