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 = group.permissions[ACCESS_COARSE_LOCATION]?.isGranted == true 41 return if (!supportsLocationAccuracy(group) || requestsBackground) { 42 backgroundPrompt 43 } else if (requestedPerms.contains(ACCESS_FINE_LOCATION)) { 44 if (coarseGranted) { 45 Prompt.LOCATION_FINE_UPGRADE 46 } else if (isFineLocationHighlighted(group)) { 47 Prompt.LOCATION_TWO_BUTTON_FINE_HIGHLIGHT 48 } else { 49 Prompt.LOCATION_TWO_BUTTON_COARSE_HIGHLIGHT 50 } 51 } else if (requestedPerms.contains(ACCESS_COARSE_LOCATION) && !coarseGranted) { 52 Prompt.LOCATION_COARSE_ONLY 53 } else { 54 backgroundPrompt 55 } 56 } 57 getDenyButtonnull58 override fun getDenyButton( 59 group: LightAppPermGroup, 60 requestedPerms: Set<String>, 61 prompt: Prompt 62 ): DenyButton { 63 return BackgroundGrantBehavior.getDenyButton(group, requestedPerms, prompt) 64 } 65 isGroupFullyGrantednull66 override fun isGroupFullyGranted( 67 group: LightAppPermGroup, 68 requestedPerms: Set<String> 69 ): Boolean { 70 val requestsBackground = requestedPerms.any { it in group.backgroundPermNames } 71 if (!supportsLocationAccuracy(group) || requestsBackground) { 72 return BackgroundGrantBehavior.isGroupFullyGranted(group, requestedPerms) 73 } 74 return isForegroundFullyGranted(group, requestedPerms) 75 } 76 isForegroundFullyGrantednull77 override fun isForegroundFullyGranted( 78 group: LightAppPermGroup, 79 requestedPerms: Set<String> 80 ): Boolean { 81 if (!supportsLocationAccuracy(group)) { 82 return BackgroundGrantBehavior.isForegroundFullyGranted(group, requestedPerms) 83 } 84 85 if (requestedPerms.contains(ACCESS_FINE_LOCATION)) { 86 return group.permissions[ACCESS_FINE_LOCATION]?.isGranted == true 87 } 88 89 return group.foreground.allowFullGroupGrant 90 } 91 isPermissionFixednull92 override fun isPermissionFixed(group: LightAppPermGroup, perm: String): Boolean { 93 if (!supportsLocationAccuracy(group) || perm != ACCESS_COARSE_LOCATION) { 94 return BackgroundGrantBehavior.isPermissionFixed(group, perm) 95 } 96 97 // If the location group is user fixed but ACCESS_COARSE_LOCATION is not, then 98 // ACCESS_FINE_LOCATION must be user fixed. In this case ACCESS_COARSE_LOCATION 99 // is still grantable. 100 return group.foreground.isUserFixed && group.permissions[perm]?.isUserFixed == true 101 } 102 supportsLocationAccuracynull103 private fun supportsLocationAccuracy(group: LightAppPermGroup): Boolean { 104 return KotlinUtils.isLocationAccuracyEnabled() && 105 group.packageInfo.targetSdkVersion >= Build.VERSION_CODES.S 106 } 107 isFineLocationHighlightednull108 private fun isFineLocationHighlighted(group: LightAppPermGroup): Boolean { 109 // Steps to decide location accuracy default state 110 // 1. If none of the FINE and COARSE isSelectedLocationAccuracy 111 // flags is set, then use default precision from device config. 112 // 2. Otherwise set to whichever isSelectedLocationAccuracy is true. 113 val coarseLocationPerm = group.allPermissions[ACCESS_COARSE_LOCATION] 114 val fineLocationPerm = group.allPermissions[ACCESS_FINE_LOCATION] 115 return if ( 116 coarseLocationPerm?.isSelectedLocationAccuracy == false && 117 fineLocationPerm?.isSelectedLocationAccuracy == false 118 ) { 119 // default location precision is true, indicates FINE 120 return true 121 } else { 122 fineLocationPerm?.isSelectedLocationAccuracy == true 123 } 124 } 125 } 126