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 17 package com.android.systemui.qs.tiles.base.interactor 18 19 import android.content.Context 20 import android.os.UserHandle 21 import androidx.annotation.VisibleForTesting 22 import androidx.annotation.WorkerThread 23 import com.android.settingslib.RestrictedLockUtils 24 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin 25 import com.android.settingslib.RestrictedLockUtilsInternal 26 import com.android.systemui.dagger.SysUISingleton 27 import com.android.systemui.dagger.qualifiers.Background 28 import com.android.systemui.plugins.ActivityStarter 29 import com.android.systemui.qs.tiles.base.interactor.DisabledByPolicyInteractor.PolicyResult 30 import javax.inject.Inject 31 import kotlinx.coroutines.CoroutineDispatcher 32 import kotlinx.coroutines.withContext 33 34 /** 35 * Provides restrictions data for the tiles. This is used in 36 * [com.android.systemui.qs.tiles.base.viewmodel.QSTileViewModelImpl] to determine if the tile is 37 * disabled based on the [com.android.systemui.qs.tiles.viewmodel.QSTileConfig.policy]. 38 */ 39 interface DisabledByPolicyInteractor { 40 41 /** 42 * Checks if the tile is restricted by the policy for a specific user. Pass the result to the 43 * [handlePolicyResult] to let the user know that the tile is disable by the admin. 44 */ isDisablednull45 suspend fun isDisabled(user: UserHandle, userRestriction: String?): PolicyResult 46 47 /** 48 * Returns true when [policyResult] is [PolicyResult.TileDisabled] and has been handled by this 49 * method. No further handling is required and the input event can be skipped at this point. 50 * 51 * Returns false when [policyResult] is [PolicyResult.TileEnabled] and this method has done 52 * nothing. 53 */ 54 fun handlePolicyResult(policyResult: PolicyResult): Boolean 55 56 sealed interface PolicyResult { 57 /** Tile has no policy restrictions. */ 58 data object TileEnabled : PolicyResult 59 60 /** 61 * Tile is disabled by policy. Pass this to [DisabledByPolicyInteractor.handlePolicyResult] 62 * to show the user info screen using 63 * [RestrictedLockUtils.getShowAdminSupportDetailsIntent]. 64 */ 65 data class TileDisabled(val admin: EnforcedAdmin) : PolicyResult 66 } 67 } 68 69 @SysUISingleton 70 class DisabledByPolicyInteractorImpl 71 @Inject 72 constructor( 73 private val context: Context, 74 private val activityStarter: ActivityStarter, 75 private val restrictedLockProxy: RestrictedLockProxy, 76 @Background private val backgroundDispatcher: CoroutineDispatcher, 77 ) : DisabledByPolicyInteractor { 78 isDisablednull79 override suspend fun isDisabled(user: UserHandle, userRestriction: String?): PolicyResult = 80 withContext(backgroundDispatcher) { 81 val admin: EnforcedAdmin = 82 restrictedLockProxy.getEnforcedAdmin(user.identifier, userRestriction) 83 ?: return@withContext PolicyResult.TileEnabled 84 85 return@withContext if ( 86 !restrictedLockProxy.hasBaseUserRestriction(user.identifier, userRestriction) 87 ) { 88 PolicyResult.TileDisabled(admin) 89 } else { 90 PolicyResult.TileEnabled 91 } 92 } 93 handlePolicyResultnull94 override fun handlePolicyResult(policyResult: PolicyResult): Boolean = 95 when (policyResult) { 96 is PolicyResult.TileEnabled -> false 97 is PolicyResult.TileDisabled -> { 98 val intent = 99 RestrictedLockUtils.getShowAdminSupportDetailsIntent(policyResult.admin) 100 activityStarter.postStartActivityDismissingKeyguard(intent, 0) 101 true 102 } 103 } 104 } 105 106 /** Mockable proxy for [RestrictedLockUtilsInternal] static methods. */ 107 @VisibleForTesting 108 class RestrictedLockProxy @Inject constructor(private val context: Context) { 109 110 @WorkerThread hasBaseUserRestrictionnull111 fun hasBaseUserRestriction(userId: Int, userRestriction: String?): Boolean = 112 RestrictedLockUtilsInternal.hasBaseUserRestriction( 113 context, 114 userRestriction, 115 userId, 116 ) 117 118 @WorkerThread 119 fun getEnforcedAdmin(userId: Int, userRestriction: String?): EnforcedAdmin? = 120 RestrictedLockUtilsInternal.checkIfRestrictionEnforced( 121 context, 122 userRestriction, 123 userId, 124 ) 125 } 126