Add a shared library for setting flags in SysUI.

This adds the FlagManager class which currently has 3 methods:
- #getFlagsFuture
- #setFlagValue
- #eraseFlag

The first makes an async call to SystemUI to retrieve the flags
it knows about. It returns a collection of Flag objects from which
one can get the id, type, and default values.

The other two are fairly self-explanatory, sending intents to
SystemUI telling to set or erase flags. Any app calling these
methods must have the FLAGS_PERMISSION defined in the FlagManager
library.

Only boolean flags are supported at the moment.

Bug: 203548827
Test: manual
Change-Id: Id15ff481edcb83c67ce4cdad6cdda27d28a40652
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index 23307de..7cf22a3 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -45,9 +45,40 @@
         ":wm_shell-aidls",
         ":wm_shell_util-sources",
     ],
+    libs: [
+        "SystemUI-flags",
+    ],
     static_libs: [
         "PluginCoreLib",
         "androidx.dynamicanimation_dynamicanimation",
+        "androidx.concurrent_concurrent-futures",
+    ],
+    java_version: "1.8",
+    min_sdk_version: "current",
+}
+
+java_library {
+    name: "SystemUI-flag-types",
+    srcs: [
+        "src/com/android/systemui/flags/Flag.kt",
+    ],
+    static_kotlin_stdlib: false,
+    java_version: "1.8",
+    min_sdk_version: "current",
+}
+
+java_library {
+    name: "SystemUIFlagsLib",
+    srcs: [
+        "src/com/android/systemui/flags/**/*.kt",
+    ],
+    static_kotlin_stdlib: false,
+    libs: [
+        "androidx.concurrent_concurrent-futures",
+        "SystemUI-flags",
+    ],
+    static_libs: [
+        "SystemUI-flag-types",
     ],
     java_version: "1.8",
     min_sdk_version: "current",
diff --git a/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt b/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt
new file mode 100644
index 0000000..68834bc
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.flags
+
+interface Flag<T> {
+    val id: Int
+    val default: T
+}
+
+data class BooleanFlag @JvmOverloads constructor(
+    override val id: Int,
+    override val default: Boolean = false
+) : Flag<Boolean>
+
+data class StringFlag @JvmOverloads constructor(
+    override val id: Int,
+    override val default: String = ""
+) : Flag<String>
+
+data class IntFlag @JvmOverloads constructor(
+    override val id: Int,
+    override val default: Int = 0
+) : Flag<Int>
+
+data class LongFlag @JvmOverloads constructor(
+    override val id: Int,
+    override val default: Long = 0
+) : Flag<Long>
+
+data class FloatFlag @JvmOverloads constructor(
+    override val id: Int,
+    override val default: Float = 0f
+) : Flag<Float>
+
+data class DoubleFlag @JvmOverloads constructor(
+    override val id: Int,
+    override val default: Double = 0.0
+) : Flag<Double>
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt b/packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt
new file mode 100644
index 0000000..89fee70
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.flags
+
+import android.content.Context
+import android.content.Intent
+import androidx.concurrent.futures.CallbackToFutureAdapter
+import com.google.common.util.concurrent.ListenableFuture
+
+class FlagManager constructor(val context: Context) {
+    companion object {
+        const val RECEIVING_PACKAGE = "com.android.systemui"
+        const val ACTION_SET_FLAG = "com.android.systemui.action.SET_FLAG"
+        const val FLAGS_PERMISSION = "com.android.systemui.permission.FLAGS"
+        const val FIELD_ID = "id"
+        const val FIELD_VALUE = "value"
+    }
+
+    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"
+            })
+    }
+
+    fun setFlagValue(id: Int, enabled: Boolean) {
+        val intent = createIntent(id)
+        intent.putExtra(FIELD_VALUE, enabled)
+
+        context.sendBroadcast(intent)
+    }
+
+    fun eraseFlag(id: Int) {
+        val intent = createIntent(id)
+
+        context.sendBroadcast(intent)
+    }
+
+    private fun createIntent(id: Int): Intent {
+        val intent = Intent(ACTION_SET_FLAG)
+        intent.setPackage(RECEIVING_PACKAGE)
+        intent.putExtra(FIELD_ID, id)
+
+        return intent
+    }
+}
\ No newline at end of file