1 /* 2 * Copyright (C) 2024 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.settingslib.metadata 18 19 import android.content.Context 20 import androidx.annotation.ArrayRes 21 import androidx.annotation.IntDef 22 import com.android.settingslib.datastore.KeyValueStore 23 import com.android.settingslib.datastore.Permissions 24 25 /** Permit of read and write request. */ 26 @IntDef( 27 ReadWritePermit.ALLOW, 28 ReadWritePermit.DISALLOW, 29 ReadWritePermit.REQUIRE_APP_PERMISSION, 30 ReadWritePermit.REQUIRE_USER_AGREEMENT, 31 ) 32 @Retention(AnnotationRetention.SOURCE) 33 @Target(AnnotationTarget.TYPE) 34 annotation class ReadWritePermit { 35 companion object { 36 /** Allow to read/write value. */ 37 const val ALLOW = 0 38 /** Disallow to read/write value (e.g. uid not allowed). */ 39 const val DISALLOW = 1 40 /** Require (runtime/special) app permission from user explicitly. */ 41 const val REQUIRE_APP_PERMISSION = 2 42 /** Require explicit user agreement (e.g. terms of service). */ 43 const val REQUIRE_USER_AGREEMENT = 3 44 45 private const val READ_PERMIT_BITS = 15 46 private const val READ_PERMIT_MASK = (1 shl 16) - 1 47 48 /** Wraps given read and write permit into an integer. */ makenull49 fun make(readPermit: @ReadWritePermit Int, writePermit: @ReadWritePermit Int): Int = 50 (writePermit shl READ_PERMIT_BITS) or readPermit 51 52 /** Extracts the read permit from given integer generated by [make]. */ 53 fun getReadPermit(readWritePermit: Int): Int = readWritePermit and READ_PERMIT_MASK 54 55 /** Extracts the write permit from given integer generated by [make]. */ 56 fun getWritePermit(readWritePermit: Int): Int = readWritePermit shr READ_PERMIT_BITS 57 } 58 } 59 60 /** The reason of preference change. */ 61 @IntDef( 62 PreferenceChangeReason.VALUE, 63 PreferenceChangeReason.STATE, 64 PreferenceChangeReason.DEPENDENT, 65 ) 66 @Retention(AnnotationRetention.SOURCE) 67 annotation class PreferenceChangeReason { 68 companion object { 69 /** Preference value is changed. */ 70 const val VALUE = 1000 71 /** Preference state (title/summary, enable state, etc.) is changed. */ 72 const val STATE = 1001 73 /** Dependent preference state is changed. */ 74 const val DEPENDENT = 1002 75 } 76 } 77 78 /** Indicates how sensitive of the data. */ 79 @Retention(AnnotationRetention.SOURCE) 80 @Target(AnnotationTarget.TYPE) 81 annotation class SensitivityLevel { 82 companion object { 83 const val UNKNOWN_SENSITIVITY = 0 84 const val NO_SENSITIVITY = 1 85 const val LOW_SENSITIVITY = 2 86 const val MEDIUM_SENSITIVITY = 3 87 const val HIGH_SENSITIVITY = 4 88 } 89 } 90 91 /** Preference metadata that has a value persisted in datastore. */ 92 interface PersistentPreference<T> : PreferenceMetadata { 93 94 /** The value type the preference is associated with. */ 95 val valueType: Class<T> 96 97 /** The sensitivity level of the preference. */ 98 val sensitivityLevel: @SensitivityLevel Int 99 get() = SensitivityLevel.UNKNOWN_SENSITIVITY 100 isPersistentnull101 override fun isPersistent(context: Context) = true 102 103 /** 104 * Returns the key-value storage of the preference. 105 * 106 * The default implementation returns the storage provided by 107 * [PreferenceScreenRegistry.getKeyValueStore]. 108 */ 109 fun storage(context: Context): KeyValueStore = 110 PreferenceScreenRegistry.getKeyValueStore(context, this)!! 111 112 /** Returns the required permissions to read preference value. */ 113 fun getReadPermissions(context: Context): Permissions? = null 114 115 /** 116 * Returns if the external application (identified by [callingPid] and [callingUid]) is 117 * permitted to read preference value. 118 * 119 * The underlying implementation does NOT need to check common states like isEnabled, 120 * isRestricted, isAvailable or permissions in [getReadPermissions]. The framework will do it 121 * behind the scene. 122 */ 123 fun getReadPermit(context: Context, callingPid: Int, callingUid: Int): @ReadWritePermit Int = 124 PreferenceScreenRegistry.defaultReadPermit 125 126 /** Returns the required permissions to write preference value. */ 127 fun getWritePermissions(context: Context): Permissions? = null 128 129 /** 130 * Returns if the external application (identified by [callingPid] and [callingUid]) is 131 * permitted to write preference value. If the write permit depends on certain value, implement 132 * the overloading [getWritePermit] instead. 133 * 134 * The underlying implementation does NOT need to check common states like isEnabled, 135 * isRestricted, isAvailable or permissions in [getWritePermissions]. The framework will do it 136 * behind the scene. 137 */ 138 fun getWritePermit(context: Context, callingPid: Int, callingUid: Int): @ReadWritePermit Int? = 139 null 140 141 /** 142 * Returns if the external application (identified by [callingPid] and [callingUid]) is 143 * permitted to write preference with given [value]. Note that if the overloading 144 * [getWritePermit] returns non null value, this method will be ignored! 145 * 146 * The underlying implementation does NOT need to check common states like isEnabled, 147 * isRestricted, isAvailable or permissions in [getWritePermissions]. The framework will do it 148 * behind the scene. 149 */ 150 fun getWritePermit( 151 context: Context, 152 value: T?, 153 callingPid: Int, 154 callingUid: Int, 155 ): @ReadWritePermit Int = PreferenceScreenRegistry.defaultWritePermit 156 } 157 158 /** Descriptor of values. */ 159 sealed interface ValueDescriptor { 160 161 /** Returns if given value (represented by index) is valid. */ 162 fun isValidValue(context: Context, index: Int): Boolean 163 } 164 165 /** Value falls into a given array. */ 166 interface DiscreteValue<T> : ValueDescriptor { 167 @get:ArrayRes val values: Int 168 169 @get:ArrayRes val valuesDescription: Int 170 getValuenull171 fun getValue(context: Context, index: Int): T 172 } 173 174 /** 175 * Value falls into a text array, whose element is [CharSequence] type. 176 * 177 * [values] resource is `<string-array>`. 178 */ 179 interface DiscreteTextValue : DiscreteValue<CharSequence> { 180 override fun isValidValue(context: Context, index: Int): Boolean { 181 if (index < 0) return false 182 return index < context.resources.getTextArray(values).size 183 } 184 185 override fun getValue(context: Context, index: Int): CharSequence = 186 context.resources.getTextArray(values)[index] 187 } 188 189 /** 190 * Value falls into a string array, whose element is [String] type. 191 * 192 * [values] resource is `<string-array>`. 193 */ 194 interface DiscreteStringValue : DiscreteValue<String> { isValidValuenull195 override fun isValidValue(context: Context, index: Int): Boolean { 196 if (index < 0) return false 197 return index < context.resources.getStringArray(values).size 198 } 199 getValuenull200 override fun getValue(context: Context, index: Int): String = 201 context.resources.getStringArray(values)[index] 202 } 203 204 /** 205 * Value falls into an integer array. 206 * 207 * [values] resource is `<integer-array>`. 208 */ 209 interface DiscreteIntValue : DiscreteValue<Int> { 210 override fun isValidValue(context: Context, index: Int): Boolean { 211 if (index < 0) return false 212 return index < context.resources.getIntArray(values).size 213 } 214 215 override fun getValue(context: Context, index: Int): Int = 216 context.resources.getIntArray(values)[index] 217 } 218