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.permissioncontroller.permission.ui.model.grantPermissions 18 19 import android.Manifest.permission.ACCESS_COARSE_LOCATION 20 import android.Manifest.permission.ACCESS_FINE_LOCATION 21 import android.os.Build 22 import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup 23 import com.android.permissioncontroller.permission.ui.model.DenyButton 24 import com.android.permissioncontroller.permission.ui.model.Prompt 25 import com.android.permissioncontroller.permission.utils.KotlinUtils 26 27 /** 28 * The Location Grant behavior is the same as the Background group behavior, up until S. After S, 29 * the fine and coarse location permissions were allowed to be granted separately, and this created 30 * a new set of grant dialogs. 31 */ 32 object LocationGrantBehavior : GrantBehavior() { getPromptnull33 override fun getPrompt( 34 group: LightAppPermGroup, 35 requestedPerms: Set<String>, 36 isSystemTriggeredPrompt: Boolean 37 ): Prompt { 38 val backgroundPrompt = BackgroundGrantBehavior.getPrompt(group, requestedPerms) 39 val requestsBackground = requestedPerms.any { it in group.backgroundPermNames } 40 val coarseGranted = 41 group.permissions[ACCESS_COARSE_LOCATION]?.isGrantedIncludingAppOp == true 42 return if (!supportsLocationAccuracy(group) || requestsBackground) { 43 backgroundPrompt 44 } else if (requestedPerms.contains(ACCESS_FINE_LOCATION)) { 45 if (coarseGranted) { 46 Prompt.LOCATION_FINE_UPGRADE 47 } else if (isFineLocationHighlighted(group)) { 48 Prompt.LOCATION_TWO_BUTTON_FINE_HIGHLIGHT 49 } else { 50 Prompt.LOCATION_TWO_BUTTON_COARSE_HIGHLIGHT 51 } 52 } else if (requestedPerms.contains(ACCESS_COARSE_LOCATION) && !coarseGranted) { 53 Prompt.LOCATION_COARSE_ONLY 54 } else { 55 backgroundPrompt 56 } 57 } 58 getDenyButtonnull59 override fun getDenyButton( 60 group: LightAppPermGroup, 61 requestedPerms: Set<String>, 62 prompt: Prompt 63 ): DenyButton { 64 return BackgroundGrantBehavior.getDenyButton(group, requestedPerms, prompt) 65 } 66 isGroupFullyGrantednull67 override fun isGroupFullyGranted( 68 group: LightAppPermGroup, 69 requestedPerms: Set<String> 70 ): Boolean { 71 val requestsBackground = requestedPerms.any { it in group.backgroundPermNames } 72 if (!supportsLocationAccuracy(group) || requestsBackground) { 73 return BackgroundGrantBehavior.isGroupFullyGranted(group, requestedPerms) 74 } 75 return isForegroundFullyGranted(group, requestedPerms) 76 } 77 isForegroundFullyGrantednull78 override fun isForegroundFullyGranted( 79 group: LightAppPermGroup, 80 requestedPerms: Set<String> 81 ): Boolean { 82 if (!supportsLocationAccuracy(group)) { 83 return BackgroundGrantBehavior.isForegroundFullyGranted(group, requestedPerms) 84 } 85 86 if (requestedPerms.contains(ACCESS_FINE_LOCATION)) { 87 return group.permissions[ACCESS_FINE_LOCATION]?.isGrantedIncludingAppOp == true 88 } 89 90 return group.foreground.isGrantedExcludingRWROrAllRWR 91 } 92 isPermissionFixednull93 override fun isPermissionFixed(group: LightAppPermGroup, perm: String): Boolean { 94 if (!supportsLocationAccuracy(group) || perm != ACCESS_COARSE_LOCATION) { 95 return BackgroundGrantBehavior.isPermissionFixed(group, perm) 96 } 97 98 // If the location group is user fixed but ACCESS_COARSE_LOCATION is not, then 99 // ACCESS_FINE_LOCATION must be user fixed. In this case ACCESS_COARSE_LOCATION 100 // is still grantable. 101 return group.foreground.isUserFixed && group.permissions[perm]?.isUserFixed == true 102 } 103 supportsLocationAccuracynull104 private fun supportsLocationAccuracy(group: LightAppPermGroup): Boolean { 105 return KotlinUtils.isLocationAccuracyEnabled() && 106 group.packageInfo.targetSdkVersion >= Build.VERSION_CODES.S 107 } 108 isFineLocationHighlightednull109 private fun isFineLocationHighlighted(group: LightAppPermGroup): Boolean { 110 // Steps to decide location accuracy default state 111 // 1. If none of the FINE and COARSE isSelectedLocationAccuracy 112 // flags is set, then use default precision from device config. 113 // 2. Otherwise set to whichever isSelectedLocationAccuracy is true. 114 val coarseLocationPerm = group.allPermissions[ACCESS_COARSE_LOCATION] 115 val fineLocationPerm = group.allPermissions[ACCESS_FINE_LOCATION] 116 return if ( 117 coarseLocationPerm?.isSelectedLocationAccuracy == false && 118 fineLocationPerm?.isSelectedLocationAccuracy == false 119 ) { 120 // default location precision is true, indicates FINE 121 return true 122 } else { 123 fineLocationPerm?.isSelectedLocationAccuracy == true 124 } 125 } 126 } 127