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