1 /* 2 * Copyright (C) 2021 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.flags 18 19 import android.annotation.BoolRes 20 import android.annotation.IntegerRes 21 import android.annotation.StringRes 22 import android.os.Parcel 23 import android.os.Parcelable 24 25 /** 26 * Base interface for flags that can change value on a running device. 27 * @property id unique id to help identify this flag. Must be unique. This will be removed soon. 28 * @property teamfood Set to true to include this flag as part of the teamfood flag. This will 29 * be removed soon. 30 * @property name Used for server-side flagging where appropriate. Also used for display. No spaces. 31 * @property namespace The server-side namespace that this flag lives under. 32 */ 33 interface Flag<T> { 34 val id: Int 35 val teamfood: Boolean 36 val name: String 37 val namespace: String 38 } 39 40 interface ParcelableFlag<T> : Flag<T>, Parcelable { 41 val default: T 42 val overridden: Boolean describeContentsnull43 override fun describeContents() = 0 44 } 45 46 interface ResourceFlag<T> : Flag<T> { 47 val resourceId: Int 48 } 49 50 interface SysPropFlag<T> : Flag<T> { 51 val default: T 52 } 53 54 /** 55 * Base class for most common boolean flags. 56 * 57 * See [UnreleasedFlag] and [ReleasedFlag] for useful implementations. 58 */ 59 // Consider using the "parcelize" kotlin library. 60 abstract class BooleanFlag constructor( 61 override val id: Int, 62 override val name: String, 63 override val namespace: String, 64 override val default: Boolean = false, 65 override val teamfood: Boolean = false, 66 override val overridden: Boolean = false 67 ) : ParcelableFlag<Boolean> { 68 69 companion object { 70 @JvmField 71 val CREATOR = object : Parcelable.Creator<BooleanFlag> { createFromParcelnull72 override fun createFromParcel(parcel: Parcel) = object : BooleanFlag(parcel) {} newArraynull73 override fun newArray(size: Int) = arrayOfNulls<BooleanFlag>(size) 74 } 75 } 76 77 private constructor(parcel: Parcel) : this( 78 id = parcel.readInt(), 79 name = parcel.readString() ?: "", 80 namespace = parcel.readString() ?: "", 81 default = parcel.readBoolean(), 82 teamfood = parcel.readBoolean(), 83 overridden = parcel.readBoolean() 84 ) 85 86 override fun writeToParcel(parcel: Parcel, flags: Int) { 87 parcel.writeInt(id) 88 parcel.writeString(name) 89 parcel.writeString(namespace) 90 parcel.writeBoolean(default) 91 parcel.writeBoolean(teamfood) 92 parcel.writeBoolean(overridden) 93 } 94 } 95 96 /** 97 * A Flag that is is false by default. 98 * 99 * It can be changed or overridden in debug builds but not in release builds. 100 */ 101 data class UnreleasedFlag constructor( 102 override val id: Int, 103 override val name: String, 104 override val namespace: String, 105 override val teamfood: Boolean = false, 106 override val overridden: Boolean = false 107 ) : BooleanFlag(id, name, namespace, false, teamfood, overridden) 108 109 /** 110 * A Flag that is true by default. 111 * 112 * It can be changed or overridden in any build, meaning it can be turned off if needed. 113 */ 114 data class ReleasedFlag constructor( 115 override val id: Int, 116 override val name: String, 117 override val namespace: String, 118 override val teamfood: Boolean = false, 119 override val overridden: Boolean = false 120 ) : BooleanFlag(id, name, namespace, true, teamfood, overridden) 121 122 /** 123 * A Flag that reads its default values from a resource overlay instead of code. 124 * 125 * Prefer [UnreleasedFlag] and [ReleasedFlag]. 126 */ 127 data class ResourceBooleanFlag constructor( 128 override val id: Int, 129 override val name: String, 130 override val namespace: String, 131 @BoolRes override val resourceId: Int, 132 override val teamfood: Boolean = false 133 ) : ResourceFlag<Boolean> 134 135 /** 136 * A Flag that can reads its overrides from System Properties. 137 * 138 * This is generally useful for flags that come from or are used _outside_ of SystemUI. 139 * 140 * Prefer [UnreleasedFlag] and [ReleasedFlag]. 141 */ 142 data class SysPropBooleanFlag constructor( 143 override val id: Int, 144 override val name: String, 145 override val namespace: String, 146 override val default: Boolean = false, 147 ) : SysPropFlag<Boolean> { 148 // TODO(b/268520433): Teamfood not supported for sysprop flags yet. 149 override val teamfood: Boolean = false 150 } 151 152 data class StringFlag constructor( 153 override val id: Int, 154 override val name: String, 155 override val namespace: String, 156 override val default: String = "", 157 override val teamfood: Boolean = false, 158 override val overridden: Boolean = false 159 ) : ParcelableFlag<String> { 160 companion object { 161 @JvmField 162 val CREATOR = object : Parcelable.Creator<StringFlag> { createFromParcelnull163 override fun createFromParcel(parcel: Parcel) = StringFlag(parcel) 164 override fun newArray(size: Int) = arrayOfNulls<StringFlag>(size) 165 } 166 } 167 168 private constructor(parcel: Parcel) : this( 169 id = parcel.readInt(), 170 name = parcel.readString() ?: "", 171 namespace = parcel.readString() ?: "", 172 default = parcel.readString() ?: "" 173 ) 174 175 override fun writeToParcel(parcel: Parcel, flags: Int) { 176 parcel.writeInt(id) 177 parcel.writeString(name) 178 parcel.writeString(namespace) 179 parcel.writeString(default) 180 } 181 } 182 183 data class ResourceStringFlag constructor( 184 override val id: Int, 185 override val name: String, 186 override val namespace: String, 187 @StringRes override val resourceId: Int, 188 override val teamfood: Boolean = false 189 ) : ResourceFlag<String> 190 191 data class IntFlag constructor( 192 override val id: Int, 193 override val name: String, 194 override val namespace: String, 195 override val default: Int = 0, 196 override val teamfood: Boolean = false, 197 override val overridden: Boolean = false 198 ) : ParcelableFlag<Int> { 199 200 companion object { 201 @JvmField 202 val CREATOR = object : Parcelable.Creator<IntFlag> { createFromParcelnull203 override fun createFromParcel(parcel: Parcel) = IntFlag(parcel) 204 override fun newArray(size: Int) = arrayOfNulls<IntFlag>(size) 205 } 206 } 207 208 private constructor(parcel: Parcel) : this( 209 id = parcel.readInt(), 210 name = parcel.readString() ?: "", 211 namespace = parcel.readString() ?: "", 212 default = parcel.readInt() 213 ) 214 215 override fun writeToParcel(parcel: Parcel, flags: Int) { 216 parcel.writeInt(id) 217 parcel.writeString(name) 218 parcel.writeString(namespace) 219 parcel.writeInt(default) 220 } 221 } 222 223 data class ResourceIntFlag constructor( 224 override val id: Int, 225 override val name: String, 226 override val namespace: String, 227 @IntegerRes override val resourceId: Int, 228 override val teamfood: Boolean = false 229 ) : ResourceFlag<Int> 230 231 data class LongFlag constructor( 232 override val id: Int, 233 override val default: Long = 0, 234 override val teamfood: Boolean = false, 235 override val name: String, 236 override val namespace: String, 237 override val overridden: Boolean = false 238 ) : ParcelableFlag<Long> { 239 240 companion object { 241 @JvmField 242 val CREATOR = object : Parcelable.Creator<LongFlag> { createFromParcelnull243 override fun createFromParcel(parcel: Parcel) = LongFlag(parcel) 244 override fun newArray(size: Int) = arrayOfNulls<LongFlag>(size) 245 } 246 } 247 248 private constructor(parcel: Parcel) : this( 249 id = parcel.readInt(), 250 name = parcel.readString() ?: "", 251 namespace = parcel.readString() ?: "", 252 default = parcel.readLong() 253 ) 254 255 override fun writeToParcel(parcel: Parcel, flags: Int) { 256 parcel.writeInt(id) 257 parcel.writeString(name) 258 parcel.writeString(namespace) 259 parcel.writeLong(default) 260 } 261 } 262 263 data class FloatFlag constructor( 264 override val id: Int, 265 override val name: String, 266 override val namespace: String, 267 override val default: Float = 0f, 268 override val teamfood: Boolean = false, 269 override val overridden: Boolean = false 270 ) : ParcelableFlag<Float> { 271 272 companion object { 273 @JvmField 274 val CREATOR = object : Parcelable.Creator<FloatFlag> { createFromParcelnull275 override fun createFromParcel(parcel: Parcel) = FloatFlag(parcel) 276 override fun newArray(size: Int) = arrayOfNulls<FloatFlag>(size) 277 } 278 } 279 280 private constructor(parcel: Parcel) : this( 281 id = parcel.readInt(), 282 name = parcel.readString() ?: "", 283 namespace = parcel.readString() ?: "", 284 default = parcel.readFloat() 285 ) 286 287 override fun writeToParcel(parcel: Parcel, flags: Int) { 288 parcel.writeInt(id) 289 parcel.writeString(name) 290 parcel.writeString(namespace) 291 parcel.writeFloat(default) 292 } 293 } 294 295 data class ResourceFloatFlag constructor( 296 override val id: Int, 297 override val name: String, 298 override val namespace: String, 299 override val resourceId: Int, 300 override val teamfood: Boolean = false, 301 ) : ResourceFlag<Int> 302 303 data class DoubleFlag constructor( 304 override val id: Int, 305 override val name: String, 306 override val namespace: String, 307 override val default: Double = 0.0, 308 override val teamfood: Boolean = false, 309 override val overridden: Boolean = false 310 ) : ParcelableFlag<Double> { 311 312 companion object { 313 @JvmField 314 val CREATOR = object : Parcelable.Creator<DoubleFlag> { createFromParcelnull315 override fun createFromParcel(parcel: Parcel) = DoubleFlag(parcel) 316 override fun newArray(size: Int) = arrayOfNulls<DoubleFlag>(size) 317 } 318 } 319 320 private constructor(parcel: Parcel) : this( 321 id = parcel.readInt(), 322 name = parcel.readString() ?: "", 323 namespace = parcel.readString() ?: "", 324 default = parcel.readDouble() 325 ) 326 327 override fun writeToParcel(parcel: Parcel, flags: Int) { 328 parcel.writeInt(id) 329 parcel.writeString(name) 330 parcel.writeString(namespace) 331 parcel.writeDouble(default) 332 } 333 } 334