1 /*
<lambda>null2  * Copyright (C) 2024 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.policy
18 
19 import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
20 import android.app.WindowConfiguration.WINDOWING_MODE_PINNED
21 import android.os.UserHandle
22 import com.android.systemui.screenshot.data.model.DisplayContentModel
23 import com.android.systemui.screenshot.data.model.ProfileType
24 import com.android.systemui.screenshot.data.repository.ProfileTypeRepository
25 import com.android.systemui.screenshot.policy.CapturePolicy.PolicyResult
26 import com.android.systemui.screenshot.policy.CapturePolicy.PolicyResult.NotMatched
27 import com.android.systemui.screenshot.policy.CaptureType.IsolatedTask
28 import com.android.window.flags.Flags
29 import javax.inject.Inject
30 import kotlinx.coroutines.flow.first
31 
32 /**
33  * Condition: When the top visible task (excluding PIP mode) belongs to a work user.
34  *
35  * Parameters: Capture only the foreground task, owned by the work user.
36  */
37 class WorkProfilePolicy
38 @Inject
39 constructor(
40     private val profileTypes: ProfileTypeRepository,
41 ) : CapturePolicy {
42 
43     override suspend fun check(content: DisplayContentModel): PolicyResult {
44         // The systemUI notification shade isn't a work app, skip.
45         if (content.systemUiState.shadeExpanded) {
46             return NotMatched(policy = NAME, reason = SHADE_EXPANDED)
47         }
48 
49         if (Flags.enableDesktopWindowingMode()) {
50             content.rootTasks.firstOrNull()?.also {
51                 if (it.windowingMode == WINDOWING_MODE_FREEFORM) {
52                     return NotMatched(policy = NAME, reason = DESKTOP_MODE_ENABLED)
53                 }
54             }
55         }
56 
57         // Find the first non PiP rootTask with a top child task owned by a work user
58         val (rootTask, childTask) =
59             content.rootTasks
60                 .filter {
61                     it.isVisible && it.windowingMode != WINDOWING_MODE_PINNED && it.hasChildTasks()
62                 }
63                 .map { it to it.childTasksTopDown().first() }
64                 .firstOrNull { (_, child) ->
65                     profileTypes.getProfileType(child.userId) == ProfileType.WORK
66                 }
67                 ?: return NotMatched(
68                     policy = NAME,
69                     reason = WORK_TASK_NOT_TOP,
70                 )
71 
72         // If matched, return parameters needed to modify the request.
73         return PolicyResult.Matched(
74             policy = NAME,
75             reason = WORK_TASK_IS_TOP,
76             CaptureParameters(
77                 type = IsolatedTask(taskId = childTask.id, taskBounds = childTask.bounds),
78                 component = childTask.componentName ?: rootTask.topActivity,
79                 owner = UserHandle.of(childTask.userId),
80             )
81         )
82     }
83 
84     companion object {
85         const val NAME = "WorkProfile"
86         const val SHADE_EXPANDED = "Notification shade is expanded"
87         const val WORK_TASK_NOT_TOP =
88             "The top-most non-PINNED task does not belong to a work profile user"
89         const val WORK_TASK_IS_TOP = "The top-most non-PINNED task belongs to a work profile user"
90         const val DESKTOP_MODE_ENABLED =
91             "enable_desktop_windowing_mode is enabled and top " +
92                 "RootTask has WINDOWING_MODE_FREEFORM"
93     }
94 }
95