1 /*
2  * Copyright (C) 2022 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.systemui.screenshot
18 
19 import android.app.ActivityTaskManager.RootTaskInfo
20 import android.app.IActivityTaskManager
21 import android.content.ComponentName
22 import android.content.Context
23 import android.graphics.Rect
24 import android.os.UserHandle
25 import android.os.UserManager
26 import android.testing.AndroidTestingRunner
27 import com.android.systemui.SysuiTestCase
28 import com.android.systemui.screenshot.ScreenshotPolicy.DisplayContentInfo
29 import com.android.systemui.screenshot.policy.ActivityType.Home
30 import com.android.systemui.screenshot.policy.ActivityType.Undefined
31 import com.android.systemui.screenshot.policy.WindowingMode.FullScreen
32 import com.android.systemui.screenshot.policy.WindowingMode.PictureInPicture
33 import com.android.systemui.screenshot.policy.newChildTask
34 import com.android.systemui.screenshot.policy.newRootTaskInfo
35 import com.android.systemui.settings.FakeDisplayTracker
36 import com.android.systemui.util.mockito.mock
37 import com.google.common.truth.Truth.assertThat
38 import kotlinx.coroutines.Dispatchers
39 import kotlinx.coroutines.runBlocking
40 import org.junit.Test
41 import org.junit.runner.RunWith
42 
43 // The following values are chosen to be distinct from commonly seen real values
44 private const val DISPLAY_ID = 100
45 private const val PRIMARY_USER = 2000
46 private const val MANAGED_PROFILE_USER = 3000
47 
48 @RunWith(AndroidTestingRunner::class)
49 class ScreenshotPolicyImplTest : SysuiTestCase() {
50 
51     @Test
testToDisplayContentInfonull52     fun testToDisplayContentInfo() {
53         assertThat(fullScreenWorkProfileTask.toDisplayContentInfo())
54             .isEqualTo(
55                 DisplayContentInfo(
56                     ComponentName(
57                         "com.google.android.apps.nbu.files",
58                         "com.google.android.apps.nbu.files.home.HomeActivity"
59                     ),
60                     Rect(0, 0, 1080, 2400),
61                     UserHandle.of(MANAGED_PROFILE_USER),
62                     65
63                 )
64             )
65     }
66 
67     @Test
<lambda>null68     fun findPrimaryContent_ignoresPipTask() = runBlocking {
69         val policy =
70             fakeTasksPolicyImpl(
71                 mContext,
72                 shadeExpanded = false,
73                 tasks = listOf(pipTask, fullScreenWorkProfileTask, launcherTask, emptyTask)
74             )
75 
76         val info = policy.findPrimaryContent(DISPLAY_ID)
77         assertThat(info).isEqualTo(fullScreenWorkProfileTask.toDisplayContentInfo())
78     }
79 
80     @Test
<lambda>null81     fun findPrimaryContent_shadeExpanded_ignoresTopTask() = runBlocking {
82         val policy =
83             fakeTasksPolicyImpl(
84                 mContext,
85                 shadeExpanded = true,
86                 tasks = listOf(fullScreenWorkProfileTask, launcherTask, emptyTask)
87             )
88 
89         val info = policy.findPrimaryContent(DISPLAY_ID)
90         assertThat(info).isEqualTo(policy.systemUiContent)
91     }
92 
93     @Test
<lambda>null94     fun findPrimaryContent_emptyTaskList() = runBlocking {
95         val policy = fakeTasksPolicyImpl(mContext, shadeExpanded = false, tasks = listOf())
96 
97         val info = policy.findPrimaryContent(DISPLAY_ID)
98         assertThat(info).isEqualTo(policy.systemUiContent)
99     }
100 
101     @Test
<lambda>null102     fun findPrimaryContent_workProfileNotOnTop() = runBlocking {
103         val policy =
104             fakeTasksPolicyImpl(
105                 mContext,
106                 shadeExpanded = false,
107                 tasks = listOf(launcherTask, fullScreenWorkProfileTask, emptyTask)
108             )
109 
110         val info = policy.findPrimaryContent(DISPLAY_ID)
111         assertThat(info).isEqualTo(launcherTask.toDisplayContentInfo())
112     }
113 
fakeTasksPolicyImplnull114     private fun fakeTasksPolicyImpl(
115         context: Context,
116         shadeExpanded: Boolean,
117         tasks: List<RootTaskInfo>
118     ): ScreenshotPolicyImpl {
119         val userManager = mock<UserManager>()
120         val atmService = mock<IActivityTaskManager>()
121         val dispatcher = Dispatchers.Unconfined
122         val displayTracker = FakeDisplayTracker(context)
123 
124         return object :
125             ScreenshotPolicyImpl(context, userManager, atmService, dispatcher, displayTracker) {
126             override suspend fun isManagedProfile(userId: Int) = (userId == MANAGED_PROFILE_USER)
127             override suspend fun getAllRootTaskInfosOnDisplay(displayId: Int) = tasks
128             override suspend fun isNotificationShadeExpanded() = shadeExpanded
129         }
130     }
131 
132     private val pipTask =
133         newRootTaskInfo(
134             taskId = 66,
135             userId = PRIMARY_USER,
136             displayId = DISPLAY_ID,
137             bounds = Rect(628, 1885, 1038, 2295),
138             windowingMode = PictureInPicture,
139             topActivity = ComponentName.unflattenFromString(YOUTUBE_PIP_ACTIVITY),
<lambda>null140         ) {
141             listOf(newChildTask(taskId = 66, userId = 0, name = YOUTUBE_HOME_ACTIVITY))
142         }
143 
144     private val fullScreenWorkProfileTask =
145         newRootTaskInfo(
146             taskId = 65,
147             userId = MANAGED_PROFILE_USER,
148             displayId = DISPLAY_ID,
149             bounds = Rect(0, 0, 1080, 2400),
150             windowingMode = FullScreen,
151             topActivity = ComponentName.unflattenFromString(FILES_HOME_ACTIVITY),
<lambda>null152         ) {
153             listOf(
154                 newChildTask(taskId = 65, userId = MANAGED_PROFILE_USER, name = FILES_HOME_ACTIVITY)
155             )
156         }
157     private val launcherTask =
158         newRootTaskInfo(
159             taskId = 1,
160             userId = PRIMARY_USER,
161             displayId = DISPLAY_ID,
162             activityType = Home,
163             windowingMode = FullScreen,
164             bounds = Rect(0, 0, 1080, 2400),
165             topActivity = ComponentName.unflattenFromString(LAUNCHER_ACTIVITY),
<lambda>null166         ) {
167             listOf(newChildTask(taskId = 1, userId = 0, name = LAUNCHER_ACTIVITY))
168         }
169 
170     private val emptyTask =
171         newRootTaskInfo(
172             taskId = 2,
173             userId = PRIMARY_USER,
174             displayId = DISPLAY_ID,
175             visible = false,
176             running = false,
177             numActivities = 0,
178             activityType = Undefined,
179             bounds = Rect(0, 0, 1080, 2400),
<lambda>null180         ) {
181             listOf(
182                 newChildTask(taskId = 3, name = ""),
183                 newChildTask(taskId = 4, name = ""),
184             )
185         }
186 }
187 
188 private const val YOUTUBE_HOME_ACTIVITY =
189     "com.google.android.youtube/" + "com.google.android.youtube.app.honeycomb.Shell\$HomeActivity"
190 
191 private const val FILES_HOME_ACTIVITY =
192     "com.google.android.apps.nbu.files/" + "com.google.android.apps.nbu.files.home.HomeActivity"
193 
194 private const val YOUTUBE_PIP_ACTIVITY =
195     "com.google.android.youtube/" +
196         "com.google.android.apps.youtube.app.watchwhile.WatchWhileActivity"
197 
198 private const val LAUNCHER_ACTIVITY =
199     "com.google.android.apps.nexuslauncher/" +
200         "com.google.android.apps.nexuslauncher.NexusLauncherActivity"
201