Add ability to read and write flags to sysprops.

Bug: 202860494
Test: manual
Change-Id: I660931492e8a2ffd1373162aab60e4abd4566db6
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/plugin/src/com/android/systemui/flags/Flags.java
index d5b9243..e983818 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/flags/Flags.java
@@ -18,6 +18,12 @@
 
 /**
  * List of {@link Flag} objects for use in SystemUI.
+ *
+ * Flag Ids are integers. They must be unique.
+ *
+ * On public release builds, flags will always return their default value. There is no way to
+ * change their value on release builds.
  */
 public class Flags {
+    public static final BooleanFlag THE_FIRST_FLAG = new BooleanFlag(1, false);
 }
diff --git a/packages/SystemUI/src-debug/com/android/systemui/flags/FeatureFlagManager.java b/packages/SystemUI/src-debug/com/android/systemui/flags/FeatureFlagManager.java
index b3a6699..b84c7bf 100644
--- a/packages/SystemUI/src-debug/com/android/systemui/flags/FeatureFlagManager.java
+++ b/packages/SystemUI/src-debug/com/android/systemui/flags/FeatureFlagManager.java
@@ -18,6 +18,9 @@
 
 import com.android.systemui.dagger.SysUISingleton;
 
+import org.json.JSONException;
+import org.json.JSONObject;
+
 import javax.inject.Inject;
 
 /**
@@ -25,28 +28,61 @@
  */
 @SysUISingleton
 public class FeatureFlagManager implements FlagReader, FlagWriter {
-    @Inject
-    public FeatureFlagManager() {}
+    private static final String SYSPROP_PREFIX = "persist.systemui.flag_";
+    private static final String FIELD_TYPE = "type";
+    private static final String FIELD_VALUE = "value";
+    private static final String TYPE_BOOLEAN = "boolean";
+    private final SystemPropertiesHelper mSystemPropertiesHelper;
 
-    public boolean isEnabled(int key, boolean defaultValue) {
-        return isEnabled(Integer.toString(key), defaultValue);
+    @Inject
+    public FeatureFlagManager(SystemPropertiesHelper systemPropertiesHelper) {
+        mSystemPropertiesHelper = systemPropertiesHelper;
     }
 
-    public boolean isEnabled(String key, boolean defaultValue) {
-        // TODO
-        return false;
+    /** Return a {@link BooleanFlag}'s value. */
+    public boolean isEnabled(int key, boolean defaultValue) {
+        String data = mSystemPropertiesHelper.get(keyToSysPropKey(key));
+        if (data.isEmpty()) {
+            return defaultValue;
+        }
+        JSONObject json;
+        try {
+            json = new JSONObject(data);
+            if (!assertType(json, TYPE_BOOLEAN)) {
+                return defaultValue;
+            }
+            return json.getBoolean(FIELD_VALUE);
+        } catch (JSONException e) {
+            // TODO: delete the property
+            return defaultValue;
+        }
     }
 
     public void setEnabled(int key, boolean value) {
-        setEnabled(Integer.toString(key), value);
-    }
-
-    public void setEnabled(String key, boolean value) {
-        // TODO
+        JSONObject json = new JSONObject();
+        try {
+            json.put(FIELD_TYPE, TYPE_BOOLEAN);
+            json.put(FIELD_VALUE, value);
+            mSystemPropertiesHelper.set(keyToSysPropKey(key), json.toString());
+        } catch (JSONException e) {
+            // no-op
+        }
     }
 
     public void addListener(Listener run) {}
 
     public void removeListener(Listener run) {}
 
+    private static String keyToSysPropKey(int key) {
+        return SYSPROP_PREFIX + key;
+    }
+
+    private static boolean assertType(JSONObject json, String type) {
+        try {
+            return json.getString(FIELD_TYPE).equals(TYPE_BOOLEAN);
+        } catch (JSONException e) {
+            return false;
+        }
+    }
+
 }
diff --git a/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt b/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt
index 6561bd5..1dc5a9f 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt
@@ -26,11 +26,19 @@
  */
 @SysUISingleton
 open class SystemPropertiesHelper @Inject constructor() {
+    fun get(name: String): String {
+        return SystemProperties.get(name)
+    }
+
     fun getBoolean(name: String, default: Boolean): Boolean {
         return SystemProperties.getBoolean(name, default)
     }
 
+    fun set(name: String, value: String) {
+        SystemProperties.set(name, value)
+    }
+
     fun set(name: String, value: Int) {
-        SystemProperties.set(name, value.toString())
+        set(name, value.toString())
     }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagManagerTest.java
new file mode 100644
index 0000000..172dcda
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagManagerTest.java
@@ -0,0 +1,46 @@
+/*
+ * 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 static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+public class FeatureFlagManagerTest extends SysuiTestCase {
+    FeatureFlagManager mFeatureFlagManager;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+
+        mFeatureFlagManager = new FeatureFlagManager();
+    }
+
+    @Test
+    public void testIsEnabled() {
+        mFeatureFlagManager.setEnabled(1, true);
+        // Again, nothing changes.
+        assertThat(mFeatureFlagManager.isEnabled(1, false)).isFalse();
+    }
+}