• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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