Loading packages/SystemUI/shared/Android.bp +2 −1 Original line number Diff line number Diff line Loading @@ -62,6 +62,7 @@ java_library { srcs: [ "src/com/android/systemui/flags/Flag.kt", ], include_srcs: true, static_kotlin_stdlib: false, java_version: "1.8", min_sdk_version: "current", Loading @@ -74,11 +75,11 @@ java_library { ], static_kotlin_stdlib: false, libs: [ "SystemUI-flags", "androidx.concurrent_concurrent-futures", ], static_libs: [ "SystemUI-flag-types", "SystemUI-flags", ], java_version: "1.8", min_sdk_version: "current", Loading packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt +127 −7 Original line number Diff line number Diff line Loading @@ -16,37 +16,157 @@ package com.android.systemui.flags interface Flag<T> { import android.os.Parcel import android.os.Parcelable interface Flag<T> : Parcelable { val id: Int val default: T override fun describeContents() = 0 } // Consider using the "parcelize" kotlin library. data class BooleanFlag @JvmOverloads constructor( override val id: Int, override val default: Boolean = false ) : Flag<Boolean> ) : Flag<Boolean> { companion object { @JvmField val CREATOR = object : Parcelable.Creator<BooleanFlag> { override fun createFromParcel(parcel: Parcel) = BooleanFlag(parcel) override fun newArray(size: Int) = arrayOfNulls<BooleanFlag>(size) } } private constructor(parcel: Parcel) : this( id = parcel.readInt(), default = parcel.readBoolean() ) override fun writeToParcel(parcel: Parcel, flags: Int) { parcel.writeInt(id) parcel.writeBoolean(default) } } data class StringFlag @JvmOverloads constructor( override val id: Int, override val default: String = "" ) : Flag<String> ) : Flag<String> { companion object { @JvmField val CREATOR = object : Parcelable.Creator<StringFlag> { override fun createFromParcel(parcel: Parcel) = StringFlag(parcel) override fun newArray(size: Int) = arrayOfNulls<StringFlag>(size) } } private constructor(parcel: Parcel) : this( id = parcel.readInt(), default = parcel.readString() ?: "" ) override fun writeToParcel(parcel: Parcel, flags: Int) { parcel.writeInt(id) parcel.writeString(default) } } data class IntFlag @JvmOverloads constructor( override val id: Int, override val default: Int = 0 ) : Flag<Int> ) : Flag<Int> { companion object { @JvmField val CREATOR = object : Parcelable.Creator<IntFlag> { override fun createFromParcel(parcel: Parcel) = IntFlag(parcel) override fun newArray(size: Int) = arrayOfNulls<IntFlag>(size) } } private constructor(parcel: Parcel) : this( id = parcel.readInt(), default = parcel.readInt() ) override fun writeToParcel(parcel: Parcel, flags: Int) { parcel.writeInt(id) parcel.writeInt(default) } } data class LongFlag @JvmOverloads constructor( override val id: Int, override val default: Long = 0 ) : Flag<Long> ) : Flag<Long> { companion object { @JvmField val CREATOR = object : Parcelable.Creator<LongFlag> { override fun createFromParcel(parcel: Parcel) = LongFlag(parcel) override fun newArray(size: Int) = arrayOfNulls<LongFlag>(size) } } private constructor(parcel: Parcel) : this( id = parcel.readInt(), default = parcel.readLong() ) override fun writeToParcel(parcel: Parcel, flags: Int) { parcel.writeInt(id) parcel.writeLong(default) } } data class FloatFlag @JvmOverloads constructor( override val id: Int, override val default: Float = 0f ) : Flag<Float> ) : Flag<Float> { companion object { @JvmField val CREATOR = object : Parcelable.Creator<FloatFlag> { override fun createFromParcel(parcel: Parcel) = FloatFlag(parcel) override fun newArray(size: Int) = arrayOfNulls<FloatFlag>(size) } } private constructor(parcel: Parcel) : this( id = parcel.readInt(), default = parcel.readFloat() ) override fun writeToParcel(parcel: Parcel, flags: Int) { parcel.writeInt(id) parcel.writeFloat(default) } } data class DoubleFlag @JvmOverloads constructor( override val id: Int, override val default: Double = 0.0 ) : Flag<Double> No newline at end of file ) : Flag<Double> { companion object { @JvmField val CREATOR = object : Parcelable.Creator<DoubleFlag> { override fun createFromParcel(parcel: Parcel) = DoubleFlag(parcel) override fun newArray(size: Int) = arrayOfNulls<DoubleFlag>(size) } } private constructor(parcel: Parcel) : this( id = parcel.readInt(), default = parcel.readDouble() ) override fun writeToParcel(parcel: Parcel, flags: Int) { parcel.writeInt(id) parcel.writeDouble(default) } } No newline at end of file packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt +29 −9 Original line number Diff line number Diff line Loading @@ -16,10 +16,13 @@ package com.android.systemui.flags import android.app.Activity import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.database.ContentObserver import android.net.Uri import android.os.Bundle import android.os.Handler import android.provider.Settings import androidx.concurrent.futures.CallbackToFutureAdapter Loading @@ -34,10 +37,12 @@ class FlagManager constructor( companion object { const val RECEIVING_PACKAGE = "com.android.systemui" const val ACTION_SET_FLAG = "com.android.systemui.action.SET_FLAG" const val ACTION_GET_FLAGS = "com.android.systemui.action.GET_FLAGS" const val FLAGS_PERMISSION = "com.android.systemui.permission.FLAGS" const val FIELD_ID = "id" const val FIELD_VALUE = "value" const val FIELD_TYPE = "type" const val FIELD_FLAGS = "flags" const val TYPE_BOOLEAN = "boolean" private const val SETTINGS_PREFIX = "systemui/flags" } Loading @@ -46,14 +51,26 @@ class FlagManager constructor( private val settingsObserver: ContentObserver = SettingsObserver() fun getFlagsFuture(): ListenableFuture<Collection<Flag<*>>> { val knownFlagMap = Flags.collectFlags() // Possible todo in the future: query systemui async to actually get the known flag ids. return CallbackToFutureAdapter.getFuture( CallbackToFutureAdapter.Resolver { completer: CallbackToFutureAdapter.Completer<Collection<Flag<*>>> -> completer.set(knownFlagMap.values as Collection<Flag<*>>) "Retrieving Flags" }) val intent = Intent(ACTION_GET_FLAGS) intent.setPackage(RECEIVING_PACKAGE) return CallbackToFutureAdapter.getFuture { completer: CallbackToFutureAdapter.Completer<Any?> -> context.sendOrderedBroadcast(intent, null, object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val extras: Bundle? = getResultExtras(false) val listOfFlags: java.util.ArrayList<Flag<*>>? = extras?.getParcelableArrayList(FIELD_FLAGS) if (listOfFlags != null) { completer.set(listOfFlags) } else { completer.setException(NoFlagResultsException()) } } }, null, Activity.RESULT_OK, "extra data", null) "QueryingFlags" } as ListenableFuture<Collection<Flag<*>>> } fun setFlagValue(id: Int, enabled: Boolean) { Loading Loading @@ -150,3 +167,6 @@ class FlagManager constructor( } class InvalidFlagStorageException : Exception("Data found but is invalid") class NoFlagResultsException : Exception( "SystemUI failed to communicate its flags back successfully") No newline at end of file packages/SystemUI/src-debug/com/android/systemui/flags/FeatureFlagManager.java +13 −4 Original line number Diff line number Diff line Loading @@ -16,10 +16,11 @@ package com.android.systemui.flags; import static com.android.systemui.flags.FlagManager.ACTION_GET_FLAGS; import static com.android.systemui.flags.FlagManager.ACTION_SET_FLAG; import static com.android.systemui.flags.FlagManager.FIELD_FLAGS; import static com.android.systemui.flags.FlagManager.FIELD_ID; import static com.android.systemui.flags.FlagManager.FIELD_VALUE; import static com.android.systemui.flags.FlagManager.FLAGS_PERMISSION; import android.content.BroadcastReceiver; import android.content.Context; Loading Loading @@ -69,8 +70,10 @@ public class FeatureFlagManager implements FlagReader, FlagWriter, Dumpable { DumpManager dumpManager) { mFlagManager = flagManager; mSecureSettings = secureSettings; IntentFilter filter = new IntentFilter(ACTION_SET_FLAG); context.registerReceiver(mReceiver, filter, FLAGS_PERMISSION, null); IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_SET_FLAG); filter.addAction(ACTION_GET_FLAGS); context.registerReceiver(mReceiver, filter, null, null); dumpManager.registerDumpable(TAG, this); } Loading Loading @@ -151,9 +154,15 @@ public class FeatureFlagManager implements FlagReader, FlagWriter, Dumpable { if (action == null) { return; } if (ACTION_SET_FLAG.equals(action)) { handleSetFlag(intent.getExtras()); } else if (ACTION_GET_FLAGS.equals(action)) { Map<Integer, Flag<?>> knownFlagMap = Flags.collectFlags(); ArrayList<Flag<?>> flags = new ArrayList<>(knownFlagMap.values()); Bundle extras = getResultExtras(true); if (extras != null) { extras.putParcelableArrayList(FIELD_FLAGS, flags); } } } Loading Loading
packages/SystemUI/shared/Android.bp +2 −1 Original line number Diff line number Diff line Loading @@ -62,6 +62,7 @@ java_library { srcs: [ "src/com/android/systemui/flags/Flag.kt", ], include_srcs: true, static_kotlin_stdlib: false, java_version: "1.8", min_sdk_version: "current", Loading @@ -74,11 +75,11 @@ java_library { ], static_kotlin_stdlib: false, libs: [ "SystemUI-flags", "androidx.concurrent_concurrent-futures", ], static_libs: [ "SystemUI-flag-types", "SystemUI-flags", ], java_version: "1.8", min_sdk_version: "current", Loading
packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt +127 −7 Original line number Diff line number Diff line Loading @@ -16,37 +16,157 @@ package com.android.systemui.flags interface Flag<T> { import android.os.Parcel import android.os.Parcelable interface Flag<T> : Parcelable { val id: Int val default: T override fun describeContents() = 0 } // Consider using the "parcelize" kotlin library. data class BooleanFlag @JvmOverloads constructor( override val id: Int, override val default: Boolean = false ) : Flag<Boolean> ) : Flag<Boolean> { companion object { @JvmField val CREATOR = object : Parcelable.Creator<BooleanFlag> { override fun createFromParcel(parcel: Parcel) = BooleanFlag(parcel) override fun newArray(size: Int) = arrayOfNulls<BooleanFlag>(size) } } private constructor(parcel: Parcel) : this( id = parcel.readInt(), default = parcel.readBoolean() ) override fun writeToParcel(parcel: Parcel, flags: Int) { parcel.writeInt(id) parcel.writeBoolean(default) } } data class StringFlag @JvmOverloads constructor( override val id: Int, override val default: String = "" ) : Flag<String> ) : Flag<String> { companion object { @JvmField val CREATOR = object : Parcelable.Creator<StringFlag> { override fun createFromParcel(parcel: Parcel) = StringFlag(parcel) override fun newArray(size: Int) = arrayOfNulls<StringFlag>(size) } } private constructor(parcel: Parcel) : this( id = parcel.readInt(), default = parcel.readString() ?: "" ) override fun writeToParcel(parcel: Parcel, flags: Int) { parcel.writeInt(id) parcel.writeString(default) } } data class IntFlag @JvmOverloads constructor( override val id: Int, override val default: Int = 0 ) : Flag<Int> ) : Flag<Int> { companion object { @JvmField val CREATOR = object : Parcelable.Creator<IntFlag> { override fun createFromParcel(parcel: Parcel) = IntFlag(parcel) override fun newArray(size: Int) = arrayOfNulls<IntFlag>(size) } } private constructor(parcel: Parcel) : this( id = parcel.readInt(), default = parcel.readInt() ) override fun writeToParcel(parcel: Parcel, flags: Int) { parcel.writeInt(id) parcel.writeInt(default) } } data class LongFlag @JvmOverloads constructor( override val id: Int, override val default: Long = 0 ) : Flag<Long> ) : Flag<Long> { companion object { @JvmField val CREATOR = object : Parcelable.Creator<LongFlag> { override fun createFromParcel(parcel: Parcel) = LongFlag(parcel) override fun newArray(size: Int) = arrayOfNulls<LongFlag>(size) } } private constructor(parcel: Parcel) : this( id = parcel.readInt(), default = parcel.readLong() ) override fun writeToParcel(parcel: Parcel, flags: Int) { parcel.writeInt(id) parcel.writeLong(default) } } data class FloatFlag @JvmOverloads constructor( override val id: Int, override val default: Float = 0f ) : Flag<Float> ) : Flag<Float> { companion object { @JvmField val CREATOR = object : Parcelable.Creator<FloatFlag> { override fun createFromParcel(parcel: Parcel) = FloatFlag(parcel) override fun newArray(size: Int) = arrayOfNulls<FloatFlag>(size) } } private constructor(parcel: Parcel) : this( id = parcel.readInt(), default = parcel.readFloat() ) override fun writeToParcel(parcel: Parcel, flags: Int) { parcel.writeInt(id) parcel.writeFloat(default) } } data class DoubleFlag @JvmOverloads constructor( override val id: Int, override val default: Double = 0.0 ) : Flag<Double> No newline at end of file ) : Flag<Double> { companion object { @JvmField val CREATOR = object : Parcelable.Creator<DoubleFlag> { override fun createFromParcel(parcel: Parcel) = DoubleFlag(parcel) override fun newArray(size: Int) = arrayOfNulls<DoubleFlag>(size) } } private constructor(parcel: Parcel) : this( id = parcel.readInt(), default = parcel.readDouble() ) override fun writeToParcel(parcel: Parcel, flags: Int) { parcel.writeInt(id) parcel.writeDouble(default) } } No newline at end of file
packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt +29 −9 Original line number Diff line number Diff line Loading @@ -16,10 +16,13 @@ package com.android.systemui.flags import android.app.Activity import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.database.ContentObserver import android.net.Uri import android.os.Bundle import android.os.Handler import android.provider.Settings import androidx.concurrent.futures.CallbackToFutureAdapter Loading @@ -34,10 +37,12 @@ class FlagManager constructor( companion object { const val RECEIVING_PACKAGE = "com.android.systemui" const val ACTION_SET_FLAG = "com.android.systemui.action.SET_FLAG" const val ACTION_GET_FLAGS = "com.android.systemui.action.GET_FLAGS" const val FLAGS_PERMISSION = "com.android.systemui.permission.FLAGS" const val FIELD_ID = "id" const val FIELD_VALUE = "value" const val FIELD_TYPE = "type" const val FIELD_FLAGS = "flags" const val TYPE_BOOLEAN = "boolean" private const val SETTINGS_PREFIX = "systemui/flags" } Loading @@ -46,14 +51,26 @@ class FlagManager constructor( private val settingsObserver: ContentObserver = SettingsObserver() fun getFlagsFuture(): ListenableFuture<Collection<Flag<*>>> { val knownFlagMap = Flags.collectFlags() // Possible todo in the future: query systemui async to actually get the known flag ids. return CallbackToFutureAdapter.getFuture( CallbackToFutureAdapter.Resolver { completer: CallbackToFutureAdapter.Completer<Collection<Flag<*>>> -> completer.set(knownFlagMap.values as Collection<Flag<*>>) "Retrieving Flags" }) val intent = Intent(ACTION_GET_FLAGS) intent.setPackage(RECEIVING_PACKAGE) return CallbackToFutureAdapter.getFuture { completer: CallbackToFutureAdapter.Completer<Any?> -> context.sendOrderedBroadcast(intent, null, object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val extras: Bundle? = getResultExtras(false) val listOfFlags: java.util.ArrayList<Flag<*>>? = extras?.getParcelableArrayList(FIELD_FLAGS) if (listOfFlags != null) { completer.set(listOfFlags) } else { completer.setException(NoFlagResultsException()) } } }, null, Activity.RESULT_OK, "extra data", null) "QueryingFlags" } as ListenableFuture<Collection<Flag<*>>> } fun setFlagValue(id: Int, enabled: Boolean) { Loading Loading @@ -150,3 +167,6 @@ class FlagManager constructor( } class InvalidFlagStorageException : Exception("Data found but is invalid") class NoFlagResultsException : Exception( "SystemUI failed to communicate its flags back successfully") No newline at end of file
packages/SystemUI/src-debug/com/android/systemui/flags/FeatureFlagManager.java +13 −4 Original line number Diff line number Diff line Loading @@ -16,10 +16,11 @@ package com.android.systemui.flags; import static com.android.systemui.flags.FlagManager.ACTION_GET_FLAGS; import static com.android.systemui.flags.FlagManager.ACTION_SET_FLAG; import static com.android.systemui.flags.FlagManager.FIELD_FLAGS; import static com.android.systemui.flags.FlagManager.FIELD_ID; import static com.android.systemui.flags.FlagManager.FIELD_VALUE; import static com.android.systemui.flags.FlagManager.FLAGS_PERMISSION; import android.content.BroadcastReceiver; import android.content.Context; Loading Loading @@ -69,8 +70,10 @@ public class FeatureFlagManager implements FlagReader, FlagWriter, Dumpable { DumpManager dumpManager) { mFlagManager = flagManager; mSecureSettings = secureSettings; IntentFilter filter = new IntentFilter(ACTION_SET_FLAG); context.registerReceiver(mReceiver, filter, FLAGS_PERMISSION, null); IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_SET_FLAG); filter.addAction(ACTION_GET_FLAGS); context.registerReceiver(mReceiver, filter, null, null); dumpManager.registerDumpable(TAG, this); } Loading Loading @@ -151,9 +154,15 @@ public class FeatureFlagManager implements FlagReader, FlagWriter, Dumpable { if (action == null) { return; } if (ACTION_SET_FLAG.equals(action)) { handleSetFlag(intent.getExtras()); } else if (ACTION_GET_FLAGS.equals(action)) { Map<Integer, Flag<?>> knownFlagMap = Flags.collectFlags(); ArrayList<Flag<?>> flags = new ArrayList<>(knownFlagMap.values()); Bundle extras = getResultExtras(true); if (extras != null) { extras.putParcelableArrayList(FIELD_FLAGS, flags); } } } Loading