Loading packages/SystemUI/src/com/android/systemui/screenshot/policy/PrivateProfilePolicy.kt +6 −8 Original line number Diff line number Diff line Loading @@ -26,8 +26,6 @@ import com.android.systemui.screenshot.policy.CapturePolicy.PolicyResult.NotMatc import com.android.systemui.screenshot.policy.CaptureType.FullScreen import javax.inject.Inject private const val POLICY_NAME = "PrivateProfile" /** * Condition: When any visible task belongs to a private user. * Loading @@ -41,7 +39,7 @@ constructor( override suspend fun check(content: DisplayContentModel): PolicyResult { // The systemUI notification shade isn't a private profile app, skip. if (content.systemUiState.shadeExpanded) { return NotMatched(policy = POLICY_NAME, reason = "Notification shade is expanded") return NotMatched(policy = NAME, reason = "Notification shade is expanded") } // Find the first visible rootTaskInfo with a child task owned by a private user Loading @@ -56,14 +54,11 @@ constructor( } ?.let { root to it } } ?: return NotMatched( policy = POLICY_NAME, reason = "No private profile tasks are visible" ) ?: return NotMatched(policy = NAME, reason = "No private profile tasks are visible") // If matched, return parameters needed to modify the request. return Matched( policy = POLICY_NAME, policy = NAME, reason = "At least one private profile task is visible", CaptureParameters( type = FullScreen(content.displayId), Loading @@ -72,4 +67,7 @@ constructor( ) ) } companion object { const val NAME = "PrivateProfile" } } packages/SystemUI/src/com/android/systemui/screenshot/policy/WorkProfilePolicy.kt +8 −5 Original line number Diff line number Diff line Loading @@ -27,8 +27,6 @@ import com.android.systemui.screenshot.policy.CaptureType.IsolatedTask import javax.inject.Inject import kotlinx.coroutines.flow.first private const val POLICY_NAME = "WorkProfile" /** * Condition: When the top visible task (excluding PIP mode) belongs to a work user. * Loading @@ -39,10 +37,11 @@ class WorkProfilePolicy constructor( private val profileTypes: ProfileTypeRepository, ) : CapturePolicy { override suspend fun check(content: DisplayContentModel): PolicyResult { // The systemUI notification shade isn't a work app, skip. if (content.systemUiState.shadeExpanded) { return NotMatched(policy = POLICY_NAME, reason = "Notification shade is expanded") return NotMatched(policy = NAME, reason = "Notification shade is expanded") } // Find the first non PiP rootTask with a top child task owned by a work user Loading @@ -54,13 +53,13 @@ constructor( profileTypes.getProfileType(child.userId) == ProfileType.WORK } ?: return NotMatched( policy = POLICY_NAME, policy = NAME, reason = "The top-most non-PINNED task does not belong to a work profile user" ) // If matched, return parameters needed to modify the request. return PolicyResult.Matched( policy = POLICY_NAME, policy = NAME, reason = "The top-most non-PINNED task ($childTask) belongs to a work profile user", CaptureParameters( type = IsolatedTask(taskId = childTask.id, taskBounds = childTask.bounds), Loading @@ -69,4 +68,8 @@ constructor( ) ) } companion object { val NAME = "WorkProfile" } } packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt +92 −122 Original line number Diff line number Diff line Loading @@ -18,11 +18,6 @@ package com.android.systemui.screenshot import android.app.ActivityTaskManager.RootTaskInfo import android.app.IActivityTaskManager import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD import android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN import android.app.WindowConfiguration.WINDOWING_MODE_PINNED import android.content.ComponentName import android.content.Context import android.graphics.Rect Loading @@ -31,6 +26,12 @@ import android.os.UserManager import android.testing.AndroidTestingRunner import com.android.systemui.SysuiTestCase import com.android.systemui.screenshot.ScreenshotPolicy.DisplayContentInfo import com.android.systemui.screenshot.policy.ActivityType.Home import com.android.systemui.screenshot.policy.ActivityType.Undefined import com.android.systemui.screenshot.policy.WindowingMode.FullScreen import com.android.systemui.screenshot.policy.WindowingMode.PictureInPicture import com.android.systemui.screenshot.policy.newChildTask import com.android.systemui.screenshot.policy.newRootTaskInfo import com.android.systemui.settings.FakeDisplayTracker import com.android.systemui.util.mockito.mock import com.google.common.truth.Truth.assertThat Loading Loading @@ -58,19 +59,18 @@ class ScreenshotPolicyImplTest : SysuiTestCase() { ), Rect(0, 0, 1080, 2400), UserHandle.of(MANAGED_PROFILE_USER), 65)) 65 ) ) } @Test fun findPrimaryContent_ignoresPipTask() = runBlocking { val policy = fakeTasksPolicyImpl( val policy = fakeTasksPolicyImpl( mContext, shadeExpanded = false, tasks = listOf( pipTask, fullScreenWorkProfileTask, launcherTask, emptyTask) tasks = listOf(pipTask, fullScreenWorkProfileTask, launcherTask, emptyTask) ) val info = policy.findPrimaryContent(DISPLAY_ID) Loading @@ -79,13 +79,11 @@ class ScreenshotPolicyImplTest : SysuiTestCase() { @Test fun findPrimaryContent_shadeExpanded_ignoresTopTask() = runBlocking { val policy = fakeTasksPolicyImpl( val policy = fakeTasksPolicyImpl( mContext, shadeExpanded = true, tasks = listOf( fullScreenWorkProfileTask, launcherTask, emptyTask) tasks = listOf(fullScreenWorkProfileTask, launcherTask, emptyTask) ) val info = policy.findPrimaryContent(DISPLAY_ID) Loading @@ -94,11 +92,7 @@ class ScreenshotPolicyImplTest : SysuiTestCase() { @Test fun findPrimaryContent_emptyTaskList() = runBlocking { val policy = fakeTasksPolicyImpl( mContext, shadeExpanded = false, tasks = listOf() ) val policy = fakeTasksPolicyImpl(mContext, shadeExpanded = false, tasks = listOf()) val info = policy.findPrimaryContent(DISPLAY_ID) assertThat(info).isEqualTo(policy.systemUiContent) Loading @@ -106,13 +100,11 @@ class ScreenshotPolicyImplTest : SysuiTestCase() { @Test fun findPrimaryContent_workProfileNotOnTop() = runBlocking { val policy = fakeTasksPolicyImpl( val policy = fakeTasksPolicyImpl( mContext, shadeExpanded = false, tasks = listOf( launcherTask, fullScreenWorkProfileTask, emptyTask) tasks = listOf(launcherTask, fullScreenWorkProfileTask, emptyTask) ) val info = policy.findPrimaryContent(DISPLAY_ID) Loading @@ -129,102 +121,80 @@ class ScreenshotPolicyImplTest : SysuiTestCase() { val dispatcher = Dispatchers.Unconfined val displayTracker = FakeDisplayTracker(context) return object : ScreenshotPolicyImpl(context, userManager, atmService, dispatcher, displayTracker) { return object : ScreenshotPolicyImpl(context, userManager, atmService, dispatcher, displayTracker) { override suspend fun isManagedProfile(userId: Int) = (userId == MANAGED_PROFILE_USER) override suspend fun getAllRootTaskInfosOnDisplay(displayId: Int) = tasks override suspend fun isNotificationShadeExpanded() = shadeExpanded } } private val pipTask = RootTaskInfo().apply { configuration.windowConfiguration.apply { windowingMode = WINDOWING_MODE_PINNED setBounds(Rect(628, 1885, 1038, 2295)) activityType = ACTIVITY_TYPE_STANDARD } displayId = DISPLAY_ID userId = PRIMARY_USER taskId = 66 visible = true isVisible = true isRunning = true numActivities = 1 topActivity = ComponentName( "com.google.android.youtube", "com.google.android.apps.youtube.app.watchwhile.WatchWhileActivity" private val pipTask = newRootTaskInfo( taskId = 66, userId = PRIMARY_USER, displayId = DISPLAY_ID, bounds = Rect(628, 1885, 1038, 2295), windowingMode = PictureInPicture, topActivity = ComponentName.unflattenFromString(YOUTUBE_PIP_ACTIVITY), ) { listOf(newChildTask(taskId = 66, userId = 0, name = YOUTUBE_HOME_ACTIVITY)) } private val fullScreenWorkProfileTask = newRootTaskInfo( taskId = 65, userId = MANAGED_PROFILE_USER, displayId = DISPLAY_ID, bounds = Rect(0, 0, 1080, 2400), windowingMode = FullScreen, topActivity = ComponentName.unflattenFromString(FILES_HOME_ACTIVITY), ) { listOf( newChildTask(taskId = 65, userId = MANAGED_PROFILE_USER, name = FILES_HOME_ACTIVITY) ) childTaskIds = intArrayOf(66) childTaskNames = arrayOf("com.google.android.youtube/" + "com.google.android.youtube.app.honeycomb.Shell\$HomeActivity") childTaskUserIds = intArrayOf(0) childTaskBounds = arrayOf(Rect(628, 1885, 1038, 2295)) } private val fullScreenWorkProfileTask = RootTaskInfo().apply { configuration.windowConfiguration.apply { windowingMode = WINDOWING_MODE_FULLSCREEN setBounds(Rect(0, 0, 1080, 2400)) activityType = ACTIVITY_TYPE_STANDARD } displayId = DISPLAY_ID userId = MANAGED_PROFILE_USER taskId = 65 visible = true isVisible = true isRunning = true numActivities = 1 topActivity = ComponentName( "com.google.android.apps.nbu.files", "com.google.android.apps.nbu.files.home.HomeActivity" private val launcherTask = newRootTaskInfo( taskId = 1, userId = PRIMARY_USER, displayId = DISPLAY_ID, activityType = Home, windowingMode = FullScreen, bounds = Rect(0, 0, 1080, 2400), topActivity = ComponentName.unflattenFromString(LAUNCHER_ACTIVITY), ) { listOf(newChildTask(taskId = 1, userId = 0, name = LAUNCHER_ACTIVITY)) } private val emptyTask = newRootTaskInfo( taskId = 2, userId = PRIMARY_USER, displayId = DISPLAY_ID, visible = false, running = false, numActivities = 0, activityType = Undefined, bounds = Rect(0, 0, 1080, 2400), ) { listOf( newChildTask(taskId = 3, name = ""), newChildTask(taskId = 4, name = ""), ) childTaskIds = intArrayOf(65) childTaskNames = arrayOf("com.google.android.apps.nbu.files/" + "com.google.android.apps.nbu.files.home.HomeActivity") childTaskUserIds = intArrayOf(MANAGED_PROFILE_USER) childTaskBounds = arrayOf(Rect(0, 0, 1080, 2400)) } private val launcherTask = RootTaskInfo().apply { configuration.windowConfiguration.apply { windowingMode = WINDOWING_MODE_FULLSCREEN setBounds(Rect(0, 0, 1080, 2400)) activityType = ACTIVITY_TYPE_HOME } displayId = DISPLAY_ID taskId = 1 userId = PRIMARY_USER visible = true isVisible = true isRunning = true numActivities = 1 topActivity = ComponentName( "com.google.android.apps.nexuslauncher", "com.google.android.apps.nexuslauncher.NexusLauncherActivity", ) childTaskIds = intArrayOf(1) childTaskNames = arrayOf("com.google.android.apps.nexuslauncher/" + "com.google.android.apps.nexuslauncher.NexusLauncherActivity") childTaskUserIds = intArrayOf(0) childTaskBounds = arrayOf(Rect(0, 0, 1080, 2400)) } private val emptyTask = RootTaskInfo().apply { configuration.windowConfiguration.apply { windowingMode = WINDOWING_MODE_FULLSCREEN setBounds(Rect(0, 0, 1080, 2400)) activityType = ACTIVITY_TYPE_UNDEFINED } displayId = DISPLAY_ID taskId = 2 userId = PRIMARY_USER visible = false isVisible = false isRunning = false numActivities = 0 childTaskIds = intArrayOf(3, 4) childTaskNames = arrayOf("", "") childTaskUserIds = intArrayOf(0, 0) childTaskBounds = arrayOf(Rect(0, 0, 1080, 2400), Rect(0, 2400, 1080, 4800)) } } const val YOUTUBE_HOME_ACTIVITY = "com.google.android.youtube/" + "com.google.android.youtube.app.honeycomb.Shell\$HomeActivity" const val FILES_HOME_ACTIVITY = "com.google.android.apps.nbu.files/" + "com.google.android.apps.nbu.files.home.HomeActivity" const val YOUTUBE_PIP_ACTIVITY = "com.google.android.youtube/" + "com.google.android.apps.youtube.app.watchwhile.WatchWhileActivity" const val LAUNCHER_ACTIVITY = "com.google.android.apps.nexuslauncher/" + "com.google.android.apps.nexuslauncher.NexusLauncherActivity" packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/NewRootTaskInfo.kt 0 → 100644 +117 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.screenshot.policy import android.app.ActivityTaskManager.RootTaskInfo import android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT import android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME import android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD import android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW import android.app.WindowConfiguration.WINDOWING_MODE_PINNED import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED import android.content.ComponentName import android.graphics.Rect import android.os.UserHandle import android.view.Display import com.android.systemui.screenshot.data.model.ChildTaskModel import com.android.systemui.screenshot.policy.ActivityType.Standard import com.android.systemui.screenshot.policy.WindowingMode.FullScreen /** An enum mapping to [android.app.WindowConfiguration] constants via [toInt]. */ enum class ActivityType(private val intValue: Int) { Undefined(ACTIVITY_TYPE_UNDEFINED), Standard(ACTIVITY_TYPE_STANDARD), Home(ACTIVITY_TYPE_HOME), Recents(ACTIVITY_TYPE_RECENTS), Assistant(ACTIVITY_TYPE_ASSISTANT), Dream(ACTIVITY_TYPE_DREAM); /** Returns the [android.app.WindowConfiguration] int constant for the type. */ fun toInt() = intValue } /** An enum mapping to [android.app.WindowConfiguration] constants via [toInt]. */ enum class WindowingMode(private val intValue: Int) { Undefined(WINDOWING_MODE_UNDEFINED), FullScreen(WINDOWING_MODE_FULLSCREEN), PictureInPicture(WINDOWING_MODE_PINNED), Freeform(WINDOWING_MODE_FREEFORM), MultiWindow(WINDOWING_MODE_MULTI_WINDOW); /** Returns the [android.app.WindowConfiguration] int constant for the mode. */ fun toInt() = intValue } /** * Constructs a child task for a [RootTaskInfo], copying [RootTaskInfo.bounds] and * [RootTaskInfo.userId] from the parent by default. */ fun RootTaskInfo.newChildTask( taskId: Int, name: String, bounds: Rect? = null, userId: Int? = null ): ChildTaskModel { return ChildTaskModel(taskId, name, bounds ?: this.bounds, userId ?: this.userId) } /** Constructs a new [RootTaskInfo]. */ fun newRootTaskInfo( taskId: Int, userId: Int = UserHandle.USER_SYSTEM, displayId: Int = Display.DEFAULT_DISPLAY, visible: Boolean = true, running: Boolean = true, activityType: ActivityType = Standard, windowingMode: WindowingMode = FullScreen, bounds: Rect? = null, topActivity: ComponentName? = null, topActivityType: ActivityType = Standard, numActivities: Int? = null, childTaskListBuilder: RootTaskInfo.() -> List<ChildTaskModel>, ): RootTaskInfo { return RootTaskInfo().apply { configuration.windowConfiguration.apply { setWindowingMode(windowingMode.toInt()) setActivityType(activityType.toInt()) setBounds(bounds) } this.bounds = bounds this.displayId = displayId this.userId = userId this.taskId = taskId this.visible = visible this.isVisible = visible this.isRunning = running this.topActivity = topActivity this.topActivityType = topActivityType.toInt() // NOTE: topActivityInfo is _not_ populated by this code val childTasks = childTaskListBuilder(this) this.numActivities = numActivities ?: childTasks.size childTaskNames = childTasks.map { it.name }.toTypedArray() childTaskIds = childTasks.map { it.id }.toIntArray() childTaskBounds = childTasks.map { it.bounds }.toTypedArray() childTaskUserIds = childTasks.map { it.userId }.toIntArray() } } Loading
packages/SystemUI/src/com/android/systemui/screenshot/policy/PrivateProfilePolicy.kt +6 −8 Original line number Diff line number Diff line Loading @@ -26,8 +26,6 @@ import com.android.systemui.screenshot.policy.CapturePolicy.PolicyResult.NotMatc import com.android.systemui.screenshot.policy.CaptureType.FullScreen import javax.inject.Inject private const val POLICY_NAME = "PrivateProfile" /** * Condition: When any visible task belongs to a private user. * Loading @@ -41,7 +39,7 @@ constructor( override suspend fun check(content: DisplayContentModel): PolicyResult { // The systemUI notification shade isn't a private profile app, skip. if (content.systemUiState.shadeExpanded) { return NotMatched(policy = POLICY_NAME, reason = "Notification shade is expanded") return NotMatched(policy = NAME, reason = "Notification shade is expanded") } // Find the first visible rootTaskInfo with a child task owned by a private user Loading @@ -56,14 +54,11 @@ constructor( } ?.let { root to it } } ?: return NotMatched( policy = POLICY_NAME, reason = "No private profile tasks are visible" ) ?: return NotMatched(policy = NAME, reason = "No private profile tasks are visible") // If matched, return parameters needed to modify the request. return Matched( policy = POLICY_NAME, policy = NAME, reason = "At least one private profile task is visible", CaptureParameters( type = FullScreen(content.displayId), Loading @@ -72,4 +67,7 @@ constructor( ) ) } companion object { const val NAME = "PrivateProfile" } }
packages/SystemUI/src/com/android/systemui/screenshot/policy/WorkProfilePolicy.kt +8 −5 Original line number Diff line number Diff line Loading @@ -27,8 +27,6 @@ import com.android.systemui.screenshot.policy.CaptureType.IsolatedTask import javax.inject.Inject import kotlinx.coroutines.flow.first private const val POLICY_NAME = "WorkProfile" /** * Condition: When the top visible task (excluding PIP mode) belongs to a work user. * Loading @@ -39,10 +37,11 @@ class WorkProfilePolicy constructor( private val profileTypes: ProfileTypeRepository, ) : CapturePolicy { override suspend fun check(content: DisplayContentModel): PolicyResult { // The systemUI notification shade isn't a work app, skip. if (content.systemUiState.shadeExpanded) { return NotMatched(policy = POLICY_NAME, reason = "Notification shade is expanded") return NotMatched(policy = NAME, reason = "Notification shade is expanded") } // Find the first non PiP rootTask with a top child task owned by a work user Loading @@ -54,13 +53,13 @@ constructor( profileTypes.getProfileType(child.userId) == ProfileType.WORK } ?: return NotMatched( policy = POLICY_NAME, policy = NAME, reason = "The top-most non-PINNED task does not belong to a work profile user" ) // If matched, return parameters needed to modify the request. return PolicyResult.Matched( policy = POLICY_NAME, policy = NAME, reason = "The top-most non-PINNED task ($childTask) belongs to a work profile user", CaptureParameters( type = IsolatedTask(taskId = childTask.id, taskBounds = childTask.bounds), Loading @@ -69,4 +68,8 @@ constructor( ) ) } companion object { val NAME = "WorkProfile" } }
packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt +92 −122 Original line number Diff line number Diff line Loading @@ -18,11 +18,6 @@ package com.android.systemui.screenshot import android.app.ActivityTaskManager.RootTaskInfo import android.app.IActivityTaskManager import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD import android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN import android.app.WindowConfiguration.WINDOWING_MODE_PINNED import android.content.ComponentName import android.content.Context import android.graphics.Rect Loading @@ -31,6 +26,12 @@ import android.os.UserManager import android.testing.AndroidTestingRunner import com.android.systemui.SysuiTestCase import com.android.systemui.screenshot.ScreenshotPolicy.DisplayContentInfo import com.android.systemui.screenshot.policy.ActivityType.Home import com.android.systemui.screenshot.policy.ActivityType.Undefined import com.android.systemui.screenshot.policy.WindowingMode.FullScreen import com.android.systemui.screenshot.policy.WindowingMode.PictureInPicture import com.android.systemui.screenshot.policy.newChildTask import com.android.systemui.screenshot.policy.newRootTaskInfo import com.android.systemui.settings.FakeDisplayTracker import com.android.systemui.util.mockito.mock import com.google.common.truth.Truth.assertThat Loading Loading @@ -58,19 +59,18 @@ class ScreenshotPolicyImplTest : SysuiTestCase() { ), Rect(0, 0, 1080, 2400), UserHandle.of(MANAGED_PROFILE_USER), 65)) 65 ) ) } @Test fun findPrimaryContent_ignoresPipTask() = runBlocking { val policy = fakeTasksPolicyImpl( val policy = fakeTasksPolicyImpl( mContext, shadeExpanded = false, tasks = listOf( pipTask, fullScreenWorkProfileTask, launcherTask, emptyTask) tasks = listOf(pipTask, fullScreenWorkProfileTask, launcherTask, emptyTask) ) val info = policy.findPrimaryContent(DISPLAY_ID) Loading @@ -79,13 +79,11 @@ class ScreenshotPolicyImplTest : SysuiTestCase() { @Test fun findPrimaryContent_shadeExpanded_ignoresTopTask() = runBlocking { val policy = fakeTasksPolicyImpl( val policy = fakeTasksPolicyImpl( mContext, shadeExpanded = true, tasks = listOf( fullScreenWorkProfileTask, launcherTask, emptyTask) tasks = listOf(fullScreenWorkProfileTask, launcherTask, emptyTask) ) val info = policy.findPrimaryContent(DISPLAY_ID) Loading @@ -94,11 +92,7 @@ class ScreenshotPolicyImplTest : SysuiTestCase() { @Test fun findPrimaryContent_emptyTaskList() = runBlocking { val policy = fakeTasksPolicyImpl( mContext, shadeExpanded = false, tasks = listOf() ) val policy = fakeTasksPolicyImpl(mContext, shadeExpanded = false, tasks = listOf()) val info = policy.findPrimaryContent(DISPLAY_ID) assertThat(info).isEqualTo(policy.systemUiContent) Loading @@ -106,13 +100,11 @@ class ScreenshotPolicyImplTest : SysuiTestCase() { @Test fun findPrimaryContent_workProfileNotOnTop() = runBlocking { val policy = fakeTasksPolicyImpl( val policy = fakeTasksPolicyImpl( mContext, shadeExpanded = false, tasks = listOf( launcherTask, fullScreenWorkProfileTask, emptyTask) tasks = listOf(launcherTask, fullScreenWorkProfileTask, emptyTask) ) val info = policy.findPrimaryContent(DISPLAY_ID) Loading @@ -129,102 +121,80 @@ class ScreenshotPolicyImplTest : SysuiTestCase() { val dispatcher = Dispatchers.Unconfined val displayTracker = FakeDisplayTracker(context) return object : ScreenshotPolicyImpl(context, userManager, atmService, dispatcher, displayTracker) { return object : ScreenshotPolicyImpl(context, userManager, atmService, dispatcher, displayTracker) { override suspend fun isManagedProfile(userId: Int) = (userId == MANAGED_PROFILE_USER) override suspend fun getAllRootTaskInfosOnDisplay(displayId: Int) = tasks override suspend fun isNotificationShadeExpanded() = shadeExpanded } } private val pipTask = RootTaskInfo().apply { configuration.windowConfiguration.apply { windowingMode = WINDOWING_MODE_PINNED setBounds(Rect(628, 1885, 1038, 2295)) activityType = ACTIVITY_TYPE_STANDARD } displayId = DISPLAY_ID userId = PRIMARY_USER taskId = 66 visible = true isVisible = true isRunning = true numActivities = 1 topActivity = ComponentName( "com.google.android.youtube", "com.google.android.apps.youtube.app.watchwhile.WatchWhileActivity" private val pipTask = newRootTaskInfo( taskId = 66, userId = PRIMARY_USER, displayId = DISPLAY_ID, bounds = Rect(628, 1885, 1038, 2295), windowingMode = PictureInPicture, topActivity = ComponentName.unflattenFromString(YOUTUBE_PIP_ACTIVITY), ) { listOf(newChildTask(taskId = 66, userId = 0, name = YOUTUBE_HOME_ACTIVITY)) } private val fullScreenWorkProfileTask = newRootTaskInfo( taskId = 65, userId = MANAGED_PROFILE_USER, displayId = DISPLAY_ID, bounds = Rect(0, 0, 1080, 2400), windowingMode = FullScreen, topActivity = ComponentName.unflattenFromString(FILES_HOME_ACTIVITY), ) { listOf( newChildTask(taskId = 65, userId = MANAGED_PROFILE_USER, name = FILES_HOME_ACTIVITY) ) childTaskIds = intArrayOf(66) childTaskNames = arrayOf("com.google.android.youtube/" + "com.google.android.youtube.app.honeycomb.Shell\$HomeActivity") childTaskUserIds = intArrayOf(0) childTaskBounds = arrayOf(Rect(628, 1885, 1038, 2295)) } private val fullScreenWorkProfileTask = RootTaskInfo().apply { configuration.windowConfiguration.apply { windowingMode = WINDOWING_MODE_FULLSCREEN setBounds(Rect(0, 0, 1080, 2400)) activityType = ACTIVITY_TYPE_STANDARD } displayId = DISPLAY_ID userId = MANAGED_PROFILE_USER taskId = 65 visible = true isVisible = true isRunning = true numActivities = 1 topActivity = ComponentName( "com.google.android.apps.nbu.files", "com.google.android.apps.nbu.files.home.HomeActivity" private val launcherTask = newRootTaskInfo( taskId = 1, userId = PRIMARY_USER, displayId = DISPLAY_ID, activityType = Home, windowingMode = FullScreen, bounds = Rect(0, 0, 1080, 2400), topActivity = ComponentName.unflattenFromString(LAUNCHER_ACTIVITY), ) { listOf(newChildTask(taskId = 1, userId = 0, name = LAUNCHER_ACTIVITY)) } private val emptyTask = newRootTaskInfo( taskId = 2, userId = PRIMARY_USER, displayId = DISPLAY_ID, visible = false, running = false, numActivities = 0, activityType = Undefined, bounds = Rect(0, 0, 1080, 2400), ) { listOf( newChildTask(taskId = 3, name = ""), newChildTask(taskId = 4, name = ""), ) childTaskIds = intArrayOf(65) childTaskNames = arrayOf("com.google.android.apps.nbu.files/" + "com.google.android.apps.nbu.files.home.HomeActivity") childTaskUserIds = intArrayOf(MANAGED_PROFILE_USER) childTaskBounds = arrayOf(Rect(0, 0, 1080, 2400)) } private val launcherTask = RootTaskInfo().apply { configuration.windowConfiguration.apply { windowingMode = WINDOWING_MODE_FULLSCREEN setBounds(Rect(0, 0, 1080, 2400)) activityType = ACTIVITY_TYPE_HOME } displayId = DISPLAY_ID taskId = 1 userId = PRIMARY_USER visible = true isVisible = true isRunning = true numActivities = 1 topActivity = ComponentName( "com.google.android.apps.nexuslauncher", "com.google.android.apps.nexuslauncher.NexusLauncherActivity", ) childTaskIds = intArrayOf(1) childTaskNames = arrayOf("com.google.android.apps.nexuslauncher/" + "com.google.android.apps.nexuslauncher.NexusLauncherActivity") childTaskUserIds = intArrayOf(0) childTaskBounds = arrayOf(Rect(0, 0, 1080, 2400)) } private val emptyTask = RootTaskInfo().apply { configuration.windowConfiguration.apply { windowingMode = WINDOWING_MODE_FULLSCREEN setBounds(Rect(0, 0, 1080, 2400)) activityType = ACTIVITY_TYPE_UNDEFINED } displayId = DISPLAY_ID taskId = 2 userId = PRIMARY_USER visible = false isVisible = false isRunning = false numActivities = 0 childTaskIds = intArrayOf(3, 4) childTaskNames = arrayOf("", "") childTaskUserIds = intArrayOf(0, 0) childTaskBounds = arrayOf(Rect(0, 0, 1080, 2400), Rect(0, 2400, 1080, 4800)) } } const val YOUTUBE_HOME_ACTIVITY = "com.google.android.youtube/" + "com.google.android.youtube.app.honeycomb.Shell\$HomeActivity" const val FILES_HOME_ACTIVITY = "com.google.android.apps.nbu.files/" + "com.google.android.apps.nbu.files.home.HomeActivity" const val YOUTUBE_PIP_ACTIVITY = "com.google.android.youtube/" + "com.google.android.apps.youtube.app.watchwhile.WatchWhileActivity" const val LAUNCHER_ACTIVITY = "com.google.android.apps.nexuslauncher/" + "com.google.android.apps.nexuslauncher.NexusLauncherActivity"
packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/NewRootTaskInfo.kt 0 → 100644 +117 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.screenshot.policy import android.app.ActivityTaskManager.RootTaskInfo import android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT import android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME import android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD import android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW import android.app.WindowConfiguration.WINDOWING_MODE_PINNED import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED import android.content.ComponentName import android.graphics.Rect import android.os.UserHandle import android.view.Display import com.android.systemui.screenshot.data.model.ChildTaskModel import com.android.systemui.screenshot.policy.ActivityType.Standard import com.android.systemui.screenshot.policy.WindowingMode.FullScreen /** An enum mapping to [android.app.WindowConfiguration] constants via [toInt]. */ enum class ActivityType(private val intValue: Int) { Undefined(ACTIVITY_TYPE_UNDEFINED), Standard(ACTIVITY_TYPE_STANDARD), Home(ACTIVITY_TYPE_HOME), Recents(ACTIVITY_TYPE_RECENTS), Assistant(ACTIVITY_TYPE_ASSISTANT), Dream(ACTIVITY_TYPE_DREAM); /** Returns the [android.app.WindowConfiguration] int constant for the type. */ fun toInt() = intValue } /** An enum mapping to [android.app.WindowConfiguration] constants via [toInt]. */ enum class WindowingMode(private val intValue: Int) { Undefined(WINDOWING_MODE_UNDEFINED), FullScreen(WINDOWING_MODE_FULLSCREEN), PictureInPicture(WINDOWING_MODE_PINNED), Freeform(WINDOWING_MODE_FREEFORM), MultiWindow(WINDOWING_MODE_MULTI_WINDOW); /** Returns the [android.app.WindowConfiguration] int constant for the mode. */ fun toInt() = intValue } /** * Constructs a child task for a [RootTaskInfo], copying [RootTaskInfo.bounds] and * [RootTaskInfo.userId] from the parent by default. */ fun RootTaskInfo.newChildTask( taskId: Int, name: String, bounds: Rect? = null, userId: Int? = null ): ChildTaskModel { return ChildTaskModel(taskId, name, bounds ?: this.bounds, userId ?: this.userId) } /** Constructs a new [RootTaskInfo]. */ fun newRootTaskInfo( taskId: Int, userId: Int = UserHandle.USER_SYSTEM, displayId: Int = Display.DEFAULT_DISPLAY, visible: Boolean = true, running: Boolean = true, activityType: ActivityType = Standard, windowingMode: WindowingMode = FullScreen, bounds: Rect? = null, topActivity: ComponentName? = null, topActivityType: ActivityType = Standard, numActivities: Int? = null, childTaskListBuilder: RootTaskInfo.() -> List<ChildTaskModel>, ): RootTaskInfo { return RootTaskInfo().apply { configuration.windowConfiguration.apply { setWindowingMode(windowingMode.toInt()) setActivityType(activityType.toInt()) setBounds(bounds) } this.bounds = bounds this.displayId = displayId this.userId = userId this.taskId = taskId this.visible = visible this.isVisible = visible this.isRunning = running this.topActivity = topActivity this.topActivityType = topActivityType.toInt() // NOTE: topActivityInfo is _not_ populated by this code val childTasks = childTaskListBuilder(this) this.numActivities = numActivities ?: childTasks.size childTaskNames = childTasks.map { it.name }.toTypedArray() childTaskIds = childTasks.map { it.id }.toIntArray() childTaskBounds = childTasks.map { it.bounds }.toTypedArray() childTaskUserIds = childTasks.map { it.userId }.toIntArray() } }