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

Commit 8bf1a3c1 authored by Robert Snoeberger's avatar Robert Snoeberger
Browse files

Move to Extension for handling plugins plus default.

Bug: 118761043
Test: KeyguardClockSwitchTest adapted and passes.
Change-Id: I747274af894845a867b0d1ca38b2fd3338798e01
parent 60854080
Loading
Loading
Loading
Loading
+59 −68
Original line number Diff line number Diff line
@@ -14,13 +14,13 @@ import androidx.annotation.VisibleForTesting;

import com.android.systemui.Dependency;
import com.android.systemui.plugins.ClockPlugin;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.policy.ExtensionController;
import com.android.systemui.statusbar.policy.ExtensionController.Extension;

import java.util.Objects;
import java.util.TimeZone;
import java.util.function.Consumer;

/**
 * Switch to show plugin clock when plugin is connected, otherwise it will show default clock.
@@ -47,43 +47,15 @@ public class KeyguardClockSwitch extends RelativeLayout {
     * or not to show it below the alternate clock.
     */
    private View mKeyguardStatusArea;
    /**
     * Used to select between plugin or default implementations of ClockPlugin interface.
     */
    private Extension<ClockPlugin> mClockExtension;
    /**
     * Consumer that accepts the a new ClockPlugin implementation when the Extension reloads.
     */
    private final Consumer<ClockPlugin> mClockPluginConsumer = plugin -> setClockPlugin(plugin);

    private final PluginListener<ClockPlugin> mClockPluginListener =
            new PluginListener<ClockPlugin>() {
                @Override
                public void onPluginConnected(ClockPlugin plugin, Context pluginContext) {
                    disconnectPlugin();
                    View smallClockView = plugin.getView();
                    if (smallClockView != null) {
                        // For now, assume that the most recently connected plugin is the
                        // selected clock face. In the future, the user should be able to
                        // pick a clock face from the available plugins.
                        mSmallClockFrame.addView(smallClockView, -1,
                                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                                        ViewGroup.LayoutParams.WRAP_CONTENT));
                        initPluginParams();
                        mClockView.setVisibility(View.GONE);
                    }
                    View bigClockView = plugin.getBigClockView();
                    if (bigClockView != null && mBigClockContainer != null) {
                        mBigClockContainer.addView(bigClockView);
                        mBigClockContainer.setVisibility(View.VISIBLE);
                    }
                    if (!plugin.shouldShowStatusArea()) {
                        mKeyguardStatusArea.setVisibility(View.GONE);
                    }
                    mClockPlugin = plugin;
                }

                @Override
                public void onPluginDisconnected(ClockPlugin plugin) {
                    if (Objects.equals(plugin, mClockPlugin)) {
                        disconnectPlugin();
                        mClockView.setVisibility(View.VISIBLE);
                        mKeyguardStatusArea.setVisibility(View.VISIBLE);
                    }
                }
            };
    private final StatusBarStateController.StateListener mStateListener =
            new StatusBarStateController.StateListener() {
                @Override
@@ -122,18 +94,61 @@ public class KeyguardClockSwitch extends RelativeLayout {
    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        Dependency.get(PluginManager.class).addPluginListener(mClockPluginListener,
                ClockPlugin.class);
        mClockExtension = Dependency.get(ExtensionController.class).newExtension(ClockPlugin.class)
                .withPlugin(ClockPlugin.class)
                .withCallback(mClockPluginConsumer)
                .build();
        Dependency.get(StatusBarStateController.class).addCallback(mStateListener);
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        Dependency.get(PluginManager.class).removePluginListener(mClockPluginListener);
        mClockExtension.destroy();
        Dependency.get(StatusBarStateController.class).removeCallback(mStateListener);
    }

    private void setClockPlugin(ClockPlugin plugin) {
        // Disconnect from existing plugin.
        if (mClockPlugin != null) {
            View smallClockView = mClockPlugin.getView();
            if (smallClockView != null && smallClockView.getParent() == mSmallClockFrame) {
                mSmallClockFrame.removeView(smallClockView);
            }
            if (mBigClockContainer != null) {
                mBigClockContainer.removeAllViews();
                mBigClockContainer.setVisibility(View.GONE);
            }
            mClockPlugin = null;
        }
        if (plugin == null) {
            mClockView.setVisibility(View.VISIBLE);
            mKeyguardStatusArea.setVisibility(View.VISIBLE);
            return;
        }
        // Attach small and big clock views to hierarchy.
        View smallClockView = plugin.getView();
        if (smallClockView != null) {
            mSmallClockFrame.addView(smallClockView, -1,
                    new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                            ViewGroup.LayoutParams.WRAP_CONTENT));
            mClockView.setVisibility(View.GONE);
        }
        View bigClockView = plugin.getBigClockView();
        if (bigClockView != null && mBigClockContainer != null) {
            mBigClockContainer.addView(bigClockView);
            mBigClockContainer.setVisibility(View.VISIBLE);
        }
        // Hide default clock.
        if (!plugin.shouldShowStatusArea()) {
            mKeyguardStatusArea.setVisibility(View.GONE);
        }
        // Initialize plugin parameters.
        mClockPlugin = plugin;
        mClockPlugin.setStyle(getPaint().getStyle());
        mClockPlugin.setTextColor(getCurrentTextColor());
    }

    /**
     * Set container for big clock face appearing behind NSSL and KeyguardStatusView.
     */
@@ -232,33 +247,9 @@ public class KeyguardClockSwitch extends RelativeLayout {
        }
    }

    /**
     * When plugin changes, set all kept parameters into newer plugin.
     */
    private void initPluginParams() {
        if (mClockPlugin != null) {
            mClockPlugin.setStyle(getPaint().getStyle());
            mClockPlugin.setTextColor(getCurrentTextColor());
        }
    }

    private void disconnectPlugin() {
        if (mClockPlugin != null) {
            View smallClockView = mClockPlugin.getView();
            if (smallClockView != null) {
                mSmallClockFrame.removeView(smallClockView);
            }
            if (mBigClockContainer != null) {
                mBigClockContainer.removeAllViews();
                mBigClockContainer.setVisibility(View.GONE);
            }
            mClockPlugin = null;
        }
    }

    @VisibleForTesting (otherwise = VisibleForTesting.NONE)
    PluginListener getClockPluginListener() {
        return mClockPluginListener;
    Consumer<ClockPlugin> getClockPluginConsumer() {
        return mClockPluginConsumer;
    }

    @VisibleForTesting (otherwise = VisibleForTesting.NONE)
+20 −66
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import static android.view.View.VISIBLE;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -42,19 +41,18 @@ import android.widget.TextClock;

import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.ClockPlugin;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateController;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.function.Consumer;

@SmallTest
@RunWith(AndroidTestingRunner.class)
// Need to run on the main thread because KeyguardSliceView$Row init checks for
@@ -62,7 +60,6 @@ import org.mockito.MockitoAnnotations;
// the keyguard_clcok_switch layout is inflated.
@RunWithLooper(setAsMainLooper = true)
public class KeyguardClockSwitchTest extends SysuiTestCase {
    private PluginManager mPluginManager;
    private FrameLayout mClockContainer;
    private StatusBarStateController.StateListener mStateListener;

@@ -73,7 +70,6 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {

    @Before
    public void setUp() {
        mPluginManager = mDependency.injectMockDependency(PluginManager.class);
        LayoutInflater layoutInflater = LayoutInflater.from(getContext());
        mKeyguardClockSwitch =
                (KeyguardClockSwitch) layoutInflater.inflate(R.layout.keyguard_clock_switch, null);
@@ -83,30 +79,13 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
        mStateListener = mKeyguardClockSwitch.getStateListener();
    }

    @Test
    public void onAttachToWindow_addPluginListener() {
        mKeyguardClockSwitch.onAttachedToWindow();

        ArgumentCaptor<PluginListener> listener = ArgumentCaptor.forClass(PluginListener.class);
        verify(mPluginManager).addPluginListener(listener.capture(), eq(ClockPlugin.class));
    }

    @Test
    public void onDetachToWindow_removePluginListener() {
        mKeyguardClockSwitch.onDetachedFromWindow();

        ArgumentCaptor<PluginListener> listener = ArgumentCaptor.forClass(PluginListener.class);
        verify(mPluginManager).removePluginListener(listener.capture());
    }

    @Test
    public void onPluginConnected_showPluginClock() {
        ClockPlugin plugin = mock(ClockPlugin.class);
        TextClock pluginView = new TextClock(getContext());
        when(plugin.getView()).thenReturn(pluginView);
        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();

        listener.onPluginConnected(plugin, null);
        mKeyguardClockSwitch.getClockPluginConsumer().accept(plugin);

        verify(mClockView).setVisibility(GONE);
        assertThat(plugin.getView().getParent()).isEqualTo(mClockContainer);
@@ -122,9 +101,8 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
        ClockPlugin plugin = mock(ClockPlugin.class);
        TextClock pluginView = new TextClock(getContext());
        when(plugin.getBigClockView()).thenReturn(pluginView);
        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
        // WHEN the plugin is connected
        listener.onPluginConnected(plugin, null);
        mKeyguardClockSwitch.getClockPluginConsumer().accept(plugin);
        // THEN the big clock container is visible and it is the parent of the
        // big clock view.
        assertThat(bigClockContainer.getVisibility()).isEqualTo(VISIBLE);
@@ -134,8 +112,7 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
    @Test
    public void onPluginConnected_nullView() {
        ClockPlugin plugin = mock(ClockPlugin.class);
        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
        listener.onPluginConnected(plugin, null);
        mKeyguardClockSwitch.getClockPluginConsumer().accept(plugin);
        verify(mClockView, never()).setVisibility(GONE);
    }

@@ -144,12 +121,11 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
        // GIVEN a plugin has already connected
        ClockPlugin plugin1 = mock(ClockPlugin.class);
        when(plugin1.getView()).thenReturn(new TextClock(getContext()));
        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
        listener.onPluginConnected(plugin1, null);
        mKeyguardClockSwitch.getClockPluginConsumer().accept(plugin1);
        // WHEN a second plugin is connected
        ClockPlugin plugin2 = mock(ClockPlugin.class);
        when(plugin2.getView()).thenReturn(new TextClock(getContext()));
        listener.onPluginConnected(plugin2, null);
        mKeyguardClockSwitch.getClockPluginConsumer().accept(plugin2);
        // THEN only the view from the second plugin should be a child of KeyguardClockSwitch.
        assertThat(plugin2.getView().getParent()).isEqualTo(mClockContainer);
        assertThat(plugin1.getView().getParent()).isNull();
@@ -161,10 +137,9 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
        TextClock pluginView = new TextClock(getContext());
        when(plugin.getView()).thenReturn(pluginView);
        mClockView.setVisibility(GONE);
        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();

        listener.onPluginConnected(plugin, null);
        listener.onPluginDisconnected(plugin);
        mKeyguardClockSwitch.getClockPluginConsumer().accept(plugin);
        mKeyguardClockSwitch.getClockPluginConsumer().accept(null);

        verify(mClockView).setVisibility(VISIBLE);
        assertThat(plugin.getView().getParent()).isNull();
@@ -180,10 +155,9 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
        ClockPlugin plugin = mock(ClockPlugin.class);
        TextClock pluginView = new TextClock(getContext());
        when(plugin.getBigClockView()).thenReturn(pluginView);
        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
        listener.onPluginConnected(plugin, null);
        // WHEN the plugin is disconnected
        listener.onPluginDisconnected(plugin);
        // WHEN the plugin is connected and then disconnected
        mKeyguardClockSwitch.getClockPluginConsumer().accept(plugin);
        mKeyguardClockSwitch.getClockPluginConsumer().accept(null);
        // THEN the big lock container is GONE and the big clock view doesn't have
        // a parent.
        assertThat(bigClockContainer.getVisibility()).isEqualTo(GONE);
@@ -193,41 +167,23 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
    @Test
    public void onPluginDisconnected_nullView() {
        ClockPlugin plugin = mock(ClockPlugin.class);
        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
        listener.onPluginConnected(plugin, null);
        listener.onPluginDisconnected(plugin);
        mKeyguardClockSwitch.getClockPluginConsumer().accept(plugin);
        mKeyguardClockSwitch.getClockPluginConsumer().accept(null);
        verify(mClockView, never()).setVisibility(GONE);
    }

    @Test
    public void onPluginDisconnected_firstOfTwoDisconnected() {
        // GIVEN two plugins are connected
        ClockPlugin plugin1 = mock(ClockPlugin.class);
        when(plugin1.getView()).thenReturn(new TextClock(getContext()));
        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
        listener.onPluginConnected(plugin1, null);
        ClockPlugin plugin2 = mock(ClockPlugin.class);
        when(plugin2.getView()).thenReturn(new TextClock(getContext()));
        listener.onPluginConnected(plugin2, null);
        // WHEN the first plugin is disconnected
        listener.onPluginDisconnected(plugin1);
        // THEN the view from the second plugin is still a child of KeyguardClockSwitch.
        assertThat(plugin2.getView().getParent()).isEqualTo(mClockContainer);
        assertThat(plugin1.getView().getParent()).isNull();
    }

    @Test
    public void onPluginDisconnected_secondOfTwoDisconnected() {
        // GIVEN two plugins are connected
        ClockPlugin plugin1 = mock(ClockPlugin.class);
        when(plugin1.getView()).thenReturn(new TextClock(getContext()));
        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
        listener.onPluginConnected(plugin1, null);
        Consumer<ClockPlugin> consumer = mKeyguardClockSwitch.getClockPluginConsumer();
        consumer.accept(plugin1);
        ClockPlugin plugin2 = mock(ClockPlugin.class);
        when(plugin2.getView()).thenReturn(new TextClock(getContext()));
        listener.onPluginConnected(plugin2, null);
        consumer.accept(plugin2);
        // WHEN the second plugin is disconnected
        listener.onPluginDisconnected(plugin2);
        consumer.accept(null);
        // THEN the default clock should be shown.
        verify(mClockView).setVisibility(VISIBLE);
        assertThat(plugin1.getView().getParent()).isNull();
@@ -246,8 +202,7 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
        ClockPlugin plugin = mock(ClockPlugin.class);
        TextClock pluginView = new TextClock(getContext());
        when(plugin.getView()).thenReturn(pluginView);
        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
        listener.onPluginConnected(plugin, null);
        mKeyguardClockSwitch.getClockPluginConsumer().accept(plugin);

        mKeyguardClockSwitch.setTextColor(Color.WHITE);

@@ -271,8 +226,7 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
        TextClock pluginView = new TextClock(getContext());
        when(plugin.getView()).thenReturn(pluginView);
        Style style = mock(Style.class);
        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
        listener.onPluginConnected(plugin, null);
        mKeyguardClockSwitch.getClockPluginConsumer().accept(plugin);

        mKeyguardClockSwitch.setStyle(style);