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