Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 61065aad authored by Dave Mankoff's avatar Dave Mankoff Committed by Automerger Merge Worker
Browse files

Merge "Add flag listeners." into sc-v2-dev am: 64eea77e

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15405312

Change-Id: Iae2f9b70f5ef583b3e5077d28aff3d5c5f30bcc2
parents 4140b2ee 64eea77e
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -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);
    }
}
+8 −0
Original line number Diff line number Diff line
@@ -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.
     *
+33 −22
Original line number Diff line number Diff line
@@ -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;
@@ -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);
    }

    /**
@@ -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);
    }
@@ -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 {
        /** */
+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();

    }
}