| /* |
| * Copyright (C) 2018 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.keyguard; |
| |
| import static android.view.View.GONE; |
| import static android.view.View.VISIBLE; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| |
| import static org.mockito.Mockito.doReturn; |
| import static org.mockito.Mockito.mock; |
| import static org.mockito.Mockito.never; |
| import static org.mockito.Mockito.verify; |
| import static org.mockito.Mockito.when; |
| |
| import android.graphics.Color; |
| import android.graphics.Paint.Style; |
| import android.test.suitebuilder.annotation.SmallTest; |
| import android.testing.AndroidTestingRunner; |
| import android.testing.TestableLooper.RunWithLooper; |
| import android.text.TextPaint; |
| import android.view.LayoutInflater; |
| import android.view.View; |
| import android.widget.FrameLayout; |
| import android.widget.TextClock; |
| |
| import com.android.keyguard.clock.ClockManager; |
| import com.android.systemui.SystemUIFactory; |
| import com.android.systemui.SysuiTestCase; |
| import com.android.systemui.plugins.ClockPlugin; |
| import com.android.systemui.plugins.statusbar.StatusBarStateController; |
| import com.android.systemui.statusbar.StatusBarState; |
| import com.android.systemui.util.InjectionInflationController; |
| |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.mockito.InjectMocks; |
| import org.mockito.Mock; |
| import org.mockito.MockitoAnnotations; |
| |
| @SmallTest |
| @RunWith(AndroidTestingRunner.class) |
| // Need to run on the main thread because KeyguardSliceView$Row init checks for |
| // the main thread before acquiring a wake lock. This class is constructed when |
| // the keyguard_clcok_switch layout is inflated. |
| @RunWithLooper(setAsMainLooper = true) |
| public class KeyguardClockSwitchTest extends SysuiTestCase { |
| private FrameLayout mClockContainer; |
| private FrameLayout mBigClockContainer; |
| private TextClock mBigClock; |
| private StatusBarStateController.StateListener mStateListener; |
| |
| @Mock |
| TextClock mClockView; |
| @InjectMocks |
| KeyguardClockSwitch mKeyguardClockSwitch; |
| |
| @Before |
| public void setUp() { |
| InjectionInflationController inflationController = new InjectionInflationController( |
| SystemUIFactory.getInstance().getRootComponent()); |
| LayoutInflater layoutInflater = inflationController |
| .injectable(LayoutInflater.from(getContext())); |
| mKeyguardClockSwitch = |
| (KeyguardClockSwitch) layoutInflater.inflate(R.layout.keyguard_clock_switch, null); |
| mClockContainer = mKeyguardClockSwitch.findViewById(R.id.clock_view); |
| mBigClockContainer = new FrameLayout(getContext()); |
| mBigClock = new TextClock(getContext()); |
| MockitoAnnotations.initMocks(this); |
| when(mClockView.getPaint()).thenReturn(mock(TextPaint.class)); |
| mStateListener = mKeyguardClockSwitch.getStateListener(); |
| } |
| |
| @Test |
| public void onPluginConnected_showPluginClock() { |
| ClockPlugin plugin = mock(ClockPlugin.class); |
| TextClock pluginView = new TextClock(getContext()); |
| when(plugin.getView()).thenReturn(pluginView); |
| |
| mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin); |
| |
| verify(mClockView).setVisibility(GONE); |
| assertThat(plugin.getView().getParent()).isEqualTo(mClockContainer); |
| } |
| |
| @Test |
| public void onPluginConnected_showPluginBigClock() { |
| // GIVEN that the container for the big clock has visibility GONE |
| mBigClockContainer.setVisibility(GONE); |
| mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer); |
| // AND the plugin returns a view for the big clock |
| ClockPlugin plugin = mock(ClockPlugin.class); |
| when(plugin.getBigClockView()).thenReturn(mBigClock); |
| // AND in the keyguard state |
| mStateListener.onStateChanged(StatusBarState.KEYGUARD); |
| // WHEN the plugin is connected |
| mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin); |
| // THEN the big clock container is visible and it is the parent of the |
| // big clock view. |
| assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE); |
| assertThat(mBigClock.getParent()).isEqualTo(mBigClockContainer); |
| } |
| |
| @Test |
| public void onPluginConnected_nullView() { |
| ClockPlugin plugin = mock(ClockPlugin.class); |
| mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin); |
| verify(mClockView, never()).setVisibility(GONE); |
| } |
| |
| @Test |
| public void onPluginConnected_showSecondPluginClock() { |
| // GIVEN a plugin has already connected |
| ClockPlugin plugin1 = mock(ClockPlugin.class); |
| when(plugin1.getView()).thenReturn(new TextClock(getContext())); |
| mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin1); |
| // WHEN a second plugin is connected |
| ClockPlugin plugin2 = mock(ClockPlugin.class); |
| when(plugin2.getView()).thenReturn(new TextClock(getContext())); |
| mKeyguardClockSwitch.getClockChangedListener().onClockChanged(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(); |
| } |
| |
| @Test |
| public void onPluginConnected_darkAmountInitialized() { |
| // GIVEN that the dark amount has already been set |
| mKeyguardClockSwitch.setDarkAmount(0.5f); |
| // WHEN a plugin is connected |
| ClockPlugin plugin = mock(ClockPlugin.class); |
| mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin); |
| // THEN dark amount should be initalized on the plugin. |
| verify(plugin).setDarkAmount(0.5f); |
| } |
| |
| @Test |
| public void onPluginDisconnected_showDefaultClock() { |
| ClockPlugin plugin = mock(ClockPlugin.class); |
| TextClock pluginView = new TextClock(getContext()); |
| when(plugin.getView()).thenReturn(pluginView); |
| mClockView.setVisibility(GONE); |
| |
| mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin); |
| mKeyguardClockSwitch.getClockChangedListener().onClockChanged(null); |
| |
| verify(mClockView).setVisibility(VISIBLE); |
| assertThat(plugin.getView().getParent()).isNull(); |
| } |
| |
| @Test |
| public void onPluginDisconnected_hidePluginBigClock() { |
| // GIVEN that the big clock container is visible |
| FrameLayout bigClockContainer = new FrameLayout(getContext()); |
| bigClockContainer.setVisibility(VISIBLE); |
| mKeyguardClockSwitch.setBigClockContainer(bigClockContainer); |
| // AND the plugin returns a view for the big clock |
| ClockPlugin plugin = mock(ClockPlugin.class); |
| TextClock pluginView = new TextClock(getContext()); |
| when(plugin.getBigClockView()).thenReturn(pluginView); |
| // AND in the keyguard state |
| mStateListener.onStateChanged(StatusBarState.KEYGUARD); |
| // WHEN the plugin is connected and then disconnected |
| mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin); |
| mKeyguardClockSwitch.getClockChangedListener().onClockChanged(null); |
| // THEN the big lock container is GONE and the big clock view doesn't have |
| // a parent. |
| assertThat(bigClockContainer.getVisibility()).isEqualTo(GONE); |
| assertThat(pluginView.getParent()).isNull(); |
| } |
| |
| @Test |
| public void onPluginDisconnected_nullView() { |
| ClockPlugin plugin = mock(ClockPlugin.class); |
| mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin); |
| mKeyguardClockSwitch.getClockChangedListener().onClockChanged(null); |
| verify(mClockView, never()).setVisibility(GONE); |
| } |
| |
| @Test |
| public void onPluginDisconnected_secondOfTwoDisconnected() { |
| // GIVEN two plugins are connected |
| ClockPlugin plugin1 = mock(ClockPlugin.class); |
| when(plugin1.getView()).thenReturn(new TextClock(getContext())); |
| ClockManager.ClockChangedListener listener = mKeyguardClockSwitch.getClockChangedListener(); |
| listener.onClockChanged(plugin1); |
| ClockPlugin plugin2 = mock(ClockPlugin.class); |
| when(plugin2.getView()).thenReturn(new TextClock(getContext())); |
| listener.onClockChanged(plugin2); |
| // WHEN the second plugin is disconnected |
| listener.onClockChanged(null); |
| // THEN the default clock should be shown. |
| verify(mClockView).setVisibility(VISIBLE); |
| assertThat(plugin1.getView().getParent()).isNull(); |
| assertThat(plugin2.getView().getParent()).isNull(); |
| } |
| |
| @Test |
| public void onPluginDisconnected_onDestroyView() { |
| // GIVEN a plugin is connected |
| ClockPlugin clockPlugin = mock(ClockPlugin.class); |
| when(clockPlugin.getView()).thenReturn(new TextClock(getContext())); |
| ClockManager.ClockChangedListener listener = mKeyguardClockSwitch.getClockChangedListener(); |
| listener.onClockChanged(clockPlugin); |
| // WHEN the plugin is disconnected |
| listener.onClockChanged(null); |
| // THEN onDestroyView is called on the plugin |
| verify(clockPlugin).onDestroyView(); |
| } |
| |
| @Test |
| public void setTextColor_defaultClockSetTextColor() { |
| mKeyguardClockSwitch.setTextColor(Color.YELLOW); |
| |
| verify(mClockView).setTextColor(Color.YELLOW); |
| } |
| |
| @Test |
| public void setTextColor_pluginClockSetTextColor() { |
| ClockPlugin plugin = mock(ClockPlugin.class); |
| TextClock pluginView = new TextClock(getContext()); |
| when(plugin.getView()).thenReturn(pluginView); |
| mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin); |
| |
| mKeyguardClockSwitch.setTextColor(Color.WHITE); |
| |
| verify(plugin).setTextColor(Color.WHITE); |
| } |
| |
| @Test |
| public void setStyle_defaultClockSetStyle() { |
| TextPaint paint = mock(TextPaint.class); |
| Style style = mock(Style.class); |
| doReturn(paint).when(mClockView).getPaint(); |
| |
| mKeyguardClockSwitch.setStyle(style); |
| |
| verify(paint).setStyle(style); |
| } |
| |
| @Test |
| public void setStyle_pluginClockSetStyle() { |
| ClockPlugin plugin = mock(ClockPlugin.class); |
| TextClock pluginView = new TextClock(getContext()); |
| when(plugin.getView()).thenReturn(pluginView); |
| Style style = mock(Style.class); |
| mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin); |
| |
| mKeyguardClockSwitch.setStyle(style); |
| |
| verify(plugin).setStyle(style); |
| } |
| |
| @Test |
| public void onStateChanged_GoneInShade() { |
| // GIVEN that the big clock container is visible |
| mBigClockContainer.setVisibility(View.VISIBLE); |
| mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer); |
| // WHEN transitioned to SHADE state |
| mStateListener.onStateChanged(StatusBarState.SHADE); |
| // THEN the container is gone. |
| assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.GONE); |
| } |
| |
| @Test |
| public void onStateChanged_VisibleInKeyguard() { |
| // GIVEN that the big clock container is gone |
| mBigClockContainer.setVisibility(View.GONE); |
| mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer); |
| // AND GIVEN that a plugin is active. |
| ClockPlugin plugin = mock(ClockPlugin.class); |
| when(plugin.getBigClockView()).thenReturn(mBigClock); |
| mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin); |
| // WHEN transitioned to KEYGUARD state |
| mStateListener.onStateChanged(StatusBarState.KEYGUARD); |
| // THEN the container is visible. |
| assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE); |
| } |
| |
| @Test |
| public void setBigClockContainer_visible() { |
| // GIVEN that the big clock container is visible |
| mBigClockContainer.setVisibility(View.VISIBLE); |
| // AND GIVEN that a plugin is active. |
| ClockPlugin plugin = mock(ClockPlugin.class); |
| when(plugin.getBigClockView()).thenReturn(mBigClock); |
| mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin); |
| // AND in the keyguard state |
| mStateListener.onStateChanged(StatusBarState.KEYGUARD); |
| // WHEN the container is associated with the clock switch |
| mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer); |
| // THEN the container remains visible. |
| assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE); |
| } |
| |
| @Test |
| public void setBigClockContainer_gone() { |
| // GIVEN that the big clock container is gone |
| mBigClockContainer.setVisibility(View.GONE); |
| // AND GIVEN that a plugin is active. |
| ClockPlugin plugin = mock(ClockPlugin.class); |
| when(plugin.getBigClockView()).thenReturn(mBigClock); |
| mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin); |
| // AND in the keyguard state |
| mStateListener.onStateChanged(StatusBarState.KEYGUARD); |
| // WHEN the container is associated with the clock switch |
| mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer); |
| // THEN the container is made visible. |
| assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE); |
| } |
| } |