1 /*
2  * Copyright (C) 2023 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 package com.android.systemui.mediaprojection.devicepolicy
17 
18 import android.app.admin.DevicePolicyManager
19 import android.os.UserHandle
20 import android.os.UserManager
21 import javax.inject.Inject
22 
23 /**
24  * Utility class to resolve if screen capture allowed for a particular target app/host app pair. It
25  * caches the state of the policies, so you need to create a new instance of this class if you want
26  * to react to updated policies state.
27  */
28 class ScreenCaptureDevicePolicyResolver
29 @Inject
30 constructor(
31     private val devicePolicyManager: DevicePolicyManager,
32     private val userManager: UserManager,
33     @PersonalProfile private val personalProfileUserHandle: UserHandle,
34     @WorkProfile private val workProfileUserHandle: UserHandle?
35 ) {
36 
37     /**
38      * Returns true if [hostAppUserHandle] is allowed to perform screen capture of
39      * [targetAppUserHandle]
40      */
isScreenCaptureAllowednull41     fun isScreenCaptureAllowed(
42         targetAppUserHandle: UserHandle,
43         hostAppUserHandle: UserHandle,
44     ): Boolean {
45         if (hostAppUserHandle.isWorkProfile() && workProfileScreenCaptureDisabled) {
46             // Disable screen capturing as host apps should not capture the screen
47             return false
48         }
49 
50         if (personalProfileScreenCaptureDisabled) {
51             // Disable screen capturing as personal apps should not capture the screen
52             return false
53         }
54 
55         if (targetAppUserHandle.isWorkProfile()) {
56             // Work profile target
57             if (workProfileScreenCaptureDisabled) {
58                 // Do not allow sharing work profile apps as work profile capturing is disabled
59                 return false
60             }
61         } else {
62             // Personal profile target
63             if (hostAppUserHandle.isWorkProfile() && disallowSharingIntoManagedProfile) {
64                 // Do not allow sharing of personal apps into work profile apps
65                 return false
66             }
67 
68             if (personalProfileScreenCaptureDisabled) {
69                 // Disable screen capturing as personal apps should not be captured
70                 return false
71             }
72         }
73 
74         return true
75     }
76 
77     /**
78      * Returns true if [hostAppUserHandle] is NOT allowed to capture an app from any profile,
79      * could be useful to finish the screen capture flow as soon as possible when the screen
80      * could not be captured at all.
81      */
isScreenCaptureCompletelyDisablednull82     fun isScreenCaptureCompletelyDisabled(hostAppUserHandle: UserHandle): Boolean {
83         val isWorkAppsCaptureDisabled =
84                 if (workProfileUserHandle != null) {
85                     !isScreenCaptureAllowed(
86                             targetAppUserHandle = workProfileUserHandle,
87                             hostAppUserHandle = hostAppUserHandle
88                     )
89                 } else true
90 
91         val isPersonalAppsCaptureDisabled =
92                 !isScreenCaptureAllowed(
93                         targetAppUserHandle = personalProfileUserHandle,
94                         hostAppUserHandle = hostAppUserHandle
95                 )
96 
97         return isWorkAppsCaptureDisabled && isPersonalAppsCaptureDisabled
98     }
99 
<lambda>null100     private val personalProfileScreenCaptureDisabled: Boolean by lazy {
101         devicePolicyManager.getScreenCaptureDisabled(
102             /* admin */ null,
103             personalProfileUserHandle.identifier
104         )
105     }
106 
<lambda>null107     private val workProfileScreenCaptureDisabled: Boolean by lazy {
108         workProfileUserHandle?.let {
109             devicePolicyManager.getScreenCaptureDisabled(/* admin */ null, it.identifier)
110         }
111             ?: false
112     }
113 
<lambda>null114     private val disallowSharingIntoManagedProfile: Boolean by lazy {
115         workProfileUserHandle?.let {
116             userManager.hasUserRestrictionForUser(
117                 UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE,
118                 it
119             )
120         }
121             ?: false
122     }
123 
isWorkProfilenull124     private fun UserHandle?.isWorkProfile(): Boolean = this == workProfileUserHandle
125 }
126