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.app.WindowConfiguration.ACTIVITY_TYPE_HOME 22 import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD 23 import android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED 24 import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN 25 import android.app.WindowConfiguration.WINDOWING_MODE_PINNED 26 import android.content.ComponentName 27 import android.content.Context 28 import android.graphics.Rect 29 import android.os.UserHandle 30 import android.os.UserManager 31 import android.testing.AndroidTestingRunner 32 import com.android.systemui.SysuiTestCase 33 import com.android.systemui.screenshot.ScreenshotPolicy.DisplayContentInfo 34 import com.android.systemui.settings.FakeDisplayTracker 35 import com.android.systemui.util.mockito.mock 36 import com.google.common.truth.Truth.assertThat 37 import kotlinx.coroutines.Dispatchers 38 import kotlinx.coroutines.runBlocking 39 import org.junit.Test 40 import org.junit.runner.RunWith 41 42 // The following values are chosen to be distinct from commonly seen real values 43 private const val DISPLAY_ID = 100 44 private const val PRIMARY_USER = 2000 45 private const val MANAGED_PROFILE_USER = 3000 46 47 @RunWith(AndroidTestingRunner::class) 48 class ScreenshotPolicyImplTest : SysuiTestCase() { 49 50 @Test 51 fun testToDisplayContentInfo() { 52 assertThat(fullScreenWorkProfileTask.toDisplayContentInfo()) 53 .isEqualTo( 54 DisplayContentInfo( 55 ComponentName( 56 "com.google.android.apps.nbu.files", 57 "com.google.android.apps.nbu.files.home.HomeActivity" 58 ), 59 Rect(0, 0, 1080, 2400), 60 UserHandle.of(MANAGED_PROFILE_USER), 61 65)) 62 } 63 64 @Test 65 fun findPrimaryContent_ignoresPipTask() = runBlocking { 66 val policy = fakeTasksPolicyImpl( 67 mContext, 68 shadeExpanded = false, 69 tasks = listOf( 70 pipTask, 71 fullScreenWorkProfileTask, 72 launcherTask, 73 emptyTask) 74 ) 75 76 val info = policy.findPrimaryContent(DISPLAY_ID) 77 assertThat(info).isEqualTo(fullScreenWorkProfileTask.toDisplayContentInfo()) 78 } 79 80 @Test 81 fun findPrimaryContent_shadeExpanded_ignoresTopTask() = runBlocking { 82 val policy = fakeTasksPolicyImpl( 83 mContext, 84 shadeExpanded = true, 85 tasks = listOf( 86 fullScreenWorkProfileTask, 87 launcherTask, 88 emptyTask) 89 ) 90 91 val info = policy.findPrimaryContent(DISPLAY_ID) 92 assertThat(info).isEqualTo(policy.systemUiContent) 93 } 94 95 @Test 96 fun findPrimaryContent_emptyTaskList() = runBlocking { 97 val policy = fakeTasksPolicyImpl( 98 mContext, 99 shadeExpanded = false, 100 tasks = listOf() 101 ) 102 103 val info = policy.findPrimaryContent(DISPLAY_ID) 104 assertThat(info).isEqualTo(policy.systemUiContent) 105 } 106 107 @Test 108 fun findPrimaryContent_workProfileNotOnTop() = runBlocking { 109 val policy = fakeTasksPolicyImpl( 110 mContext, 111 shadeExpanded = false, 112 tasks = listOf( 113 launcherTask, 114 fullScreenWorkProfileTask, 115 emptyTask) 116 ) 117 118 val info = policy.findPrimaryContent(DISPLAY_ID) 119 assertThat(info).isEqualTo(launcherTask.toDisplayContentInfo()) 120 } 121 122 private fun fakeTasksPolicyImpl( 123 context: Context, 124 shadeExpanded: Boolean, 125 tasks: List<RootTaskInfo> 126 ): ScreenshotPolicyImpl { 127 val userManager = mock<UserManager>() 128 val atmService = mock<IActivityTaskManager>() 129 val dispatcher = Dispatchers.Unconfined 130 val displayTracker = FakeDisplayTracker(context) 131 132 return object : ScreenshotPolicyImpl(context, userManager, atmService, dispatcher, 133 displayTracker) { 134 override suspend fun isManagedProfile(userId: Int) = (userId == MANAGED_PROFILE_USER) 135 override suspend fun getAllRootTaskInfosOnDisplay(displayId: Int) = tasks 136 override suspend fun isNotificationShadeExpanded() = shadeExpanded 137 } 138 } 139 140 private val pipTask = RootTaskInfo().apply { 141 configuration.windowConfiguration.apply { 142 windowingMode = WINDOWING_MODE_PINNED 143 bounds = Rect(628, 1885, 1038, 2295) 144 activityType = ACTIVITY_TYPE_STANDARD 145 } 146 displayId = DISPLAY_ID 147 userId = PRIMARY_USER 148 taskId = 66 149 visible = true 150 isVisible = true 151 isRunning = true 152 numActivities = 1 153 topActivity = ComponentName( 154 "com.google.android.youtube", 155 "com.google.android.apps.youtube.app.watchwhile.WatchWhileActivity" 156 ) 157 childTaskIds = intArrayOf(66) 158 childTaskNames = arrayOf("com.google.android.youtube/" + 159 "com.google.android.youtube.app.honeycomb.Shell\$HomeActivity") 160 childTaskUserIds = intArrayOf(0) 161 childTaskBounds = arrayOf(Rect(628, 1885, 1038, 2295)) 162 } 163 164 private val fullScreenWorkProfileTask = RootTaskInfo().apply { 165 configuration.windowConfiguration.apply { 166 windowingMode = WINDOWING_MODE_FULLSCREEN 167 bounds = Rect(0, 0, 1080, 2400) 168 activityType = ACTIVITY_TYPE_STANDARD 169 } 170 displayId = DISPLAY_ID 171 userId = MANAGED_PROFILE_USER 172 taskId = 65 173 visible = true 174 isVisible = true 175 isRunning = true 176 numActivities = 1 177 topActivity = ComponentName( 178 "com.google.android.apps.nbu.files", 179 "com.google.android.apps.nbu.files.home.HomeActivity" 180 ) 181 childTaskIds = intArrayOf(65) 182 childTaskNames = arrayOf("com.google.android.apps.nbu.files/" + 183 "com.google.android.apps.nbu.files.home.HomeActivity") 184 childTaskUserIds = intArrayOf(MANAGED_PROFILE_USER) 185 childTaskBounds = arrayOf(Rect(0, 0, 1080, 2400)) 186 } 187 188 private val launcherTask = RootTaskInfo().apply { 189 configuration.windowConfiguration.apply { 190 windowingMode = WINDOWING_MODE_FULLSCREEN 191 bounds = Rect(0, 0, 1080, 2400) 192 activityType = ACTIVITY_TYPE_HOME 193 } 194 displayId = DISPLAY_ID 195 taskId = 1 196 userId = PRIMARY_USER 197 visible = true 198 isVisible = true 199 isRunning = true 200 numActivities = 1 201 topActivity = ComponentName( 202 "com.google.android.apps.nexuslauncher", 203 "com.google.android.apps.nexuslauncher.NexusLauncherActivity", 204 ) 205 childTaskIds = intArrayOf(1) 206 childTaskNames = arrayOf("com.google.android.apps.nexuslauncher/" + 207 "com.google.android.apps.nexuslauncher.NexusLauncherActivity") 208 childTaskUserIds = intArrayOf(0) 209 childTaskBounds = arrayOf(Rect(0, 0, 1080, 2400)) 210 } 211 212 private val emptyTask = RootTaskInfo().apply { 213 configuration.windowConfiguration.apply { 214 windowingMode = WINDOWING_MODE_FULLSCREEN 215 bounds = Rect(0, 0, 1080, 2400) 216 activityType = ACTIVITY_TYPE_UNDEFINED 217 } 218 displayId = DISPLAY_ID 219 taskId = 2 220 userId = PRIMARY_USER 221 visible = false 222 isVisible = false 223 isRunning = false 224 numActivities = 0 225 childTaskIds = intArrayOf(3, 4) 226 childTaskNames = arrayOf("", "") 227 childTaskUserIds = intArrayOf(0, 0) 228 childTaskBounds = arrayOf(Rect(0, 0, 1080, 2400), Rect(0, 2400, 1080, 4800)) 229 } 230 } 231