Loading packages/SystemUI/plugin/src/com/android/systemui/plugins/FlagReaderPlugin.java +12 −0 Original line number Diff line number Diff line Loading @@ -56,4 +56,16 @@ public interface FlagReaderPlugin extends Plugin { default double getValue(int id, double def) { return def; } /** Add a listener to be alerted when any flag changes. */ default void addListener(Listener listener) {} /** Remove a listener to be alerted when any flag changes. */ default void removeListener(Listener listener) {} /** A simple listener to be alerted when a flag changes. */ interface Listener { /** */ void onFlagChanged(int id); } } packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java +8 −0 Original line number Diff line number Diff line Loading @@ -114,6 +114,14 @@ public class FeatureFlagReader { return mPlugin.getValue(flag.getId(), flag.getDefault()); } void addListener(FlagReaderPlugin.Listener listener) { mPlugin.addListener(listener); } void removeListener(FlagReaderPlugin.Listener listener) { mPlugin.removeListener(listener); } /** * Returns true if the specified feature flag has been enabled. * Loading packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java +33 −22 Original line number Diff line number Diff line Loading @@ -19,11 +19,14 @@ package com.android.systemui.flags; import android.content.Context; import android.util.FeatureFlagUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.R; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.plugins.FlagReaderPlugin; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.inject.Inject; Loading @@ -37,11 +40,26 @@ import javax.inject.Inject; public class FeatureFlags { private final FeatureFlagReader mFlagReader; private final Context mContext; private final Map<Integer, Flag<?>> mFlagMap = new HashMap<>(); private final Map<Integer, List<Listener>> mListeners = new HashMap<>(); @Inject public FeatureFlags(FeatureFlagReader flagReader, Context context) { mFlagReader = flagReader; mContext = context; flagReader.addListener(mListener); } private final FlagReaderPlugin.Listener mListener = id -> { if (mListeners.containsKey(id) && mFlagMap.containsKey(id)) { mListeners.get(id).forEach(listener -> listener.onFlagChanged(mFlagMap.get(id))); } }; @VisibleForTesting void addFlag(Flag flag) { mFlagMap.put(flag.getId(), flag); } /** Loading Loading @@ -92,6 +110,20 @@ public class FeatureFlags { return mFlagReader.getValue(flag); } /** Add a listener for a specific flag. */ public void addFlagListener(Flag<?> flag, Listener listener) { mListeners.putIfAbsent(flag.getId(), new ArrayList<>()); mListeners.get(flag.getId()).add(listener); mFlagMap.putIfAbsent(flag.getId(), flag); } /** Remove a listener for a specific flag. */ public void removeFlagListener(Flag<?> flag, Listener listener) { if (mListeners.containsKey(flag.getId())) { mListeners.get(flag.getId()).remove(listener); } } public boolean isNewNotifPipelineEnabled() { return mFlagReader.isEnabled(R.bool.flag_notification_pipeline2); } Loading Loading @@ -160,27 +192,6 @@ public class FeatureFlags { return FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL); } private Map<Integer, Flag<?>> collectFlags() { Map<Integer, Flag<?>> flags = new HashMap<>(); Field[] fields = this.getClass().getFields(); for (Field field : fields) { Class<?> t = field.getType(); if (Flag.class.isAssignableFrom(t)) { try { //flags.add((Flag<?>) field.get(null)); Flag flag = (Flag) field.get(null); flags.put(flag.getId(), flag); } catch (IllegalAccessException e) { // no-op } } } return flags; } /** Simple interface for beinga alerted when a specific flag changes value. */ public interface Listener { /** */ Loading packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsTest.java 0 → 100644 +111 −0 Original line number Diff line number Diff line /* * 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 static org.mockito.Mockito.verify; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.FlagReaderPlugin; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @SmallTest public class FeatureFlagsTest extends SysuiTestCase { @Mock FeatureFlagReader mFeatureFlagReader; private FeatureFlags mFeatureFlags; @Before public void setup() { MockitoAnnotations.initMocks(this); mFeatureFlags = new FeatureFlags(mFeatureFlagReader, getContext()); } @Test public void testAddListener() { Flag<?> flag = new BooleanFlag(1); mFeatureFlags.addFlag(flag); // Assert and capture that a plugin listener was added. ArgumentCaptor<FlagReaderPlugin.Listener> pluginListenerCaptor = ArgumentCaptor.forClass(FlagReaderPlugin.Listener.class); verify(mFeatureFlagReader).addListener(pluginListenerCaptor.capture()); FlagReaderPlugin.Listener pluginListener = pluginListenerCaptor.getValue(); // Signal a change. No listeners, so no real effect. pluginListener.onFlagChanged(flag.getId()); // Add a listener for the flag final Flag<?>[] changedFlag = {null}; FeatureFlags.Listener listener = f -> changedFlag[0] = f; mFeatureFlags.addFlagListener(flag, listener); // No changes seen yet. assertThat(changedFlag[0]).isNull(); // Signal a change. pluginListener.onFlagChanged(flag.getId()); // Assert that the change was for the correct flag. assertThat(changedFlag[0]).isEqualTo(flag); } @Test public void testRemoveListener() { Flag<?> flag = new BooleanFlag(1); mFeatureFlags.addFlag(flag); // Assert and capture that a plugin listener was added. ArgumentCaptor<FlagReaderPlugin.Listener> pluginListenerCaptor = ArgumentCaptor.forClass(FlagReaderPlugin.Listener.class); verify(mFeatureFlagReader).addListener(pluginListenerCaptor.capture()); FlagReaderPlugin.Listener pluginListener = pluginListenerCaptor.getValue(); // Add a listener for the flag final Flag<?>[] changedFlag = {null}; FeatureFlags.Listener listener = f -> changedFlag[0] = f; mFeatureFlags.addFlagListener(flag, listener); // Signal a change. pluginListener.onFlagChanged(flag.getId()); // Assert that the change was for the correct flag. assertThat(changedFlag[0]).isEqualTo(flag); changedFlag[0] = null; // Now remove the listener. mFeatureFlags.removeFlagListener(flag, listener); // Signal a change. pluginListener.onFlagChanged(flag.getId()); // Assert that the change was not triggered assertThat(changedFlag[0]).isNull(); } } Loading
packages/SystemUI/plugin/src/com/android/systemui/plugins/FlagReaderPlugin.java +12 −0 Original line number Diff line number Diff line Loading @@ -56,4 +56,16 @@ public interface FlagReaderPlugin extends Plugin { default double getValue(int id, double def) { return def; } /** Add a listener to be alerted when any flag changes. */ default void addListener(Listener listener) {} /** Remove a listener to be alerted when any flag changes. */ default void removeListener(Listener listener) {} /** A simple listener to be alerted when a flag changes. */ interface Listener { /** */ void onFlagChanged(int id); } }
packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java +8 −0 Original line number Diff line number Diff line Loading @@ -114,6 +114,14 @@ public class FeatureFlagReader { return mPlugin.getValue(flag.getId(), flag.getDefault()); } void addListener(FlagReaderPlugin.Listener listener) { mPlugin.addListener(listener); } void removeListener(FlagReaderPlugin.Listener listener) { mPlugin.removeListener(listener); } /** * Returns true if the specified feature flag has been enabled. * Loading
packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java +33 −22 Original line number Diff line number Diff line Loading @@ -19,11 +19,14 @@ package com.android.systemui.flags; import android.content.Context; import android.util.FeatureFlagUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.R; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.plugins.FlagReaderPlugin; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.inject.Inject; Loading @@ -37,11 +40,26 @@ import javax.inject.Inject; public class FeatureFlags { private final FeatureFlagReader mFlagReader; private final Context mContext; private final Map<Integer, Flag<?>> mFlagMap = new HashMap<>(); private final Map<Integer, List<Listener>> mListeners = new HashMap<>(); @Inject public FeatureFlags(FeatureFlagReader flagReader, Context context) { mFlagReader = flagReader; mContext = context; flagReader.addListener(mListener); } private final FlagReaderPlugin.Listener mListener = id -> { if (mListeners.containsKey(id) && mFlagMap.containsKey(id)) { mListeners.get(id).forEach(listener -> listener.onFlagChanged(mFlagMap.get(id))); } }; @VisibleForTesting void addFlag(Flag flag) { mFlagMap.put(flag.getId(), flag); } /** Loading Loading @@ -92,6 +110,20 @@ public class FeatureFlags { return mFlagReader.getValue(flag); } /** Add a listener for a specific flag. */ public void addFlagListener(Flag<?> flag, Listener listener) { mListeners.putIfAbsent(flag.getId(), new ArrayList<>()); mListeners.get(flag.getId()).add(listener); mFlagMap.putIfAbsent(flag.getId(), flag); } /** Remove a listener for a specific flag. */ public void removeFlagListener(Flag<?> flag, Listener listener) { if (mListeners.containsKey(flag.getId())) { mListeners.get(flag.getId()).remove(listener); } } public boolean isNewNotifPipelineEnabled() { return mFlagReader.isEnabled(R.bool.flag_notification_pipeline2); } Loading Loading @@ -160,27 +192,6 @@ public class FeatureFlags { return FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL); } private Map<Integer, Flag<?>> collectFlags() { Map<Integer, Flag<?>> flags = new HashMap<>(); Field[] fields = this.getClass().getFields(); for (Field field : fields) { Class<?> t = field.getType(); if (Flag.class.isAssignableFrom(t)) { try { //flags.add((Flag<?>) field.get(null)); Flag flag = (Flag) field.get(null); flags.put(flag.getId(), flag); } catch (IllegalAccessException e) { // no-op } } } return flags; } /** Simple interface for beinga alerted when a specific flag changes value. */ public interface Listener { /** */ Loading
packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsTest.java 0 → 100644 +111 −0 Original line number Diff line number Diff line /* * 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 static org.mockito.Mockito.verify; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.FlagReaderPlugin; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @SmallTest public class FeatureFlagsTest extends SysuiTestCase { @Mock FeatureFlagReader mFeatureFlagReader; private FeatureFlags mFeatureFlags; @Before public void setup() { MockitoAnnotations.initMocks(this); mFeatureFlags = new FeatureFlags(mFeatureFlagReader, getContext()); } @Test public void testAddListener() { Flag<?> flag = new BooleanFlag(1); mFeatureFlags.addFlag(flag); // Assert and capture that a plugin listener was added. ArgumentCaptor<FlagReaderPlugin.Listener> pluginListenerCaptor = ArgumentCaptor.forClass(FlagReaderPlugin.Listener.class); verify(mFeatureFlagReader).addListener(pluginListenerCaptor.capture()); FlagReaderPlugin.Listener pluginListener = pluginListenerCaptor.getValue(); // Signal a change. No listeners, so no real effect. pluginListener.onFlagChanged(flag.getId()); // Add a listener for the flag final Flag<?>[] changedFlag = {null}; FeatureFlags.Listener listener = f -> changedFlag[0] = f; mFeatureFlags.addFlagListener(flag, listener); // No changes seen yet. assertThat(changedFlag[0]).isNull(); // Signal a change. pluginListener.onFlagChanged(flag.getId()); // Assert that the change was for the correct flag. assertThat(changedFlag[0]).isEqualTo(flag); } @Test public void testRemoveListener() { Flag<?> flag = new BooleanFlag(1); mFeatureFlags.addFlag(flag); // Assert and capture that a plugin listener was added. ArgumentCaptor<FlagReaderPlugin.Listener> pluginListenerCaptor = ArgumentCaptor.forClass(FlagReaderPlugin.Listener.class); verify(mFeatureFlagReader).addListener(pluginListenerCaptor.capture()); FlagReaderPlugin.Listener pluginListener = pluginListenerCaptor.getValue(); // Add a listener for the flag final Flag<?>[] changedFlag = {null}; FeatureFlags.Listener listener = f -> changedFlag[0] = f; mFeatureFlags.addFlagListener(flag, listener); // Signal a change. pluginListener.onFlagChanged(flag.getId()); // Assert that the change was for the correct flag. assertThat(changedFlag[0]).isEqualTo(flag); changedFlag[0] = null; // Now remove the listener. mFeatureFlags.removeFlagListener(flag, listener); // Signal a change. pluginListener.onFlagChanged(flag.getId()); // Assert that the change was not triggered assertThat(changedFlag[0]).isNull(); } }