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

Commit 44b93686 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Move to Extension for handling plugins plus default."

parents 959d407a 8bf1a3c1
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);