• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package com.android.keyguard;
18 
19 import static android.view.View.GONE;
20 import static android.view.View.VISIBLE;
21 
22 import static com.google.common.truth.Truth.assertThat;
23 
24 import static org.mockito.Mockito.doReturn;
25 import static org.mockito.Mockito.mock;
26 import static org.mockito.Mockito.never;
27 import static org.mockito.Mockito.verify;
28 import static org.mockito.Mockito.when;
29 
30 import android.content.Context;
31 import android.graphics.Color;
32 import android.graphics.Paint.Style;
33 import android.test.suitebuilder.annotation.SmallTest;
34 import android.testing.AndroidTestingRunner;
35 import android.testing.TestableLooper.RunWithLooper;
36 import android.text.TextPaint;
37 import android.util.AttributeSet;
38 import android.view.LayoutInflater;
39 import android.view.View;
40 import android.widget.FrameLayout;
41 import android.widget.TextClock;
42 
43 import com.android.keyguard.clock.ClockManager;
44 import com.android.systemui.R;
45 import com.android.systemui.SystemUIFactory;
46 import com.android.systemui.SysuiTestCase;
47 import com.android.systemui.plugins.ClockPlugin;
48 import com.android.systemui.plugins.statusbar.StatusBarStateController;
49 import com.android.systemui.statusbar.StatusBarState;
50 import com.android.systemui.util.InjectionInflationController;
51 
52 import org.junit.Before;
53 import org.junit.Test;
54 import org.junit.runner.RunWith;
55 import org.mockito.InjectMocks;
56 import org.mockito.Mock;
57 import org.mockito.MockitoAnnotations;
58 
59 @SmallTest
60 @RunWith(AndroidTestingRunner.class)
61 // Need to run on the main thread because KeyguardSliceView$Row init checks for
62 // the main thread before acquiring a wake lock. This class is constructed when
63 // the keyguard_clcok_switch layout is inflated.
64 @RunWithLooper(setAsMainLooper = true)
65 public class KeyguardClockSwitchTest extends SysuiTestCase {
66     private FrameLayout mClockContainer;
67     private FrameLayout mBigClockContainer;
68     private TextClock mBigClock;
69     private StatusBarStateController.StateListener mStateListener;
70 
71     @Mock
72     TextClock mClockView;
73     View mMockKeyguardSliceView;
74     @InjectMocks
75     KeyguardClockSwitch mKeyguardClockSwitch;
76 
77     @Before
setUp()78     public void setUp() {
79         mMockKeyguardSliceView = mock(KeyguardSliceView.class);
80         when(mMockKeyguardSliceView.getContext()).thenReturn(mContext);
81         when(mMockKeyguardSliceView.findViewById(R.id.keyguard_status_area))
82                 .thenReturn(mMockKeyguardSliceView);
83 
84         InjectionInflationController inflationController = new InjectionInflationController(
85                 SystemUIFactory.getInstance().getRootComponent());
86         LayoutInflater layoutInflater = inflationController
87                 .injectable(LayoutInflater.from(getContext()));
88         layoutInflater.setPrivateFactory(new LayoutInflater.Factory2() {
89 
90             @Override
91             public View onCreateView(View parent, String name, Context context,
92                     AttributeSet attrs) {
93                 return onCreateView(name, context, attrs);
94             }
95 
96             @Override
97             public View onCreateView(String name, Context context, AttributeSet attrs) {
98                 if ("com.android.keyguard.KeyguardSliceView".equals(name)) {
99                     return mMockKeyguardSliceView;
100                 }
101                 return null;
102             }
103         });
104         mKeyguardClockSwitch =
105                 (KeyguardClockSwitch) layoutInflater.inflate(R.layout.keyguard_clock_switch, null);
106         mClockContainer = mKeyguardClockSwitch.findViewById(R.id.clock_view);
107         mBigClockContainer = new FrameLayout(getContext());
108         mBigClock = new TextClock(getContext());
109         MockitoAnnotations.initMocks(this);
110         when(mClockView.getPaint()).thenReturn(mock(TextPaint.class));
111         mStateListener = mKeyguardClockSwitch.getStateListener();
112     }
113 
114     @Test
onPluginConnected_showPluginClock()115     public void onPluginConnected_showPluginClock() {
116         ClockPlugin plugin = mock(ClockPlugin.class);
117         TextClock pluginView = new TextClock(getContext());
118         when(plugin.getView()).thenReturn(pluginView);
119 
120         mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
121 
122         verify(mClockView).setVisibility(GONE);
123         assertThat(plugin.getView().getParent()).isEqualTo(mClockContainer);
124     }
125 
126     @Test
onPluginConnected_showPluginBigClock()127     public void onPluginConnected_showPluginBigClock() {
128         // GIVEN that the container for the big clock has visibility GONE
129         mBigClockContainer.setVisibility(GONE);
130         mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
131         // AND the plugin returns a view for the big clock
132         ClockPlugin plugin = mock(ClockPlugin.class);
133         when(plugin.getBigClockView()).thenReturn(mBigClock);
134         // AND in the keyguard state
135         mStateListener.onStateChanged(StatusBarState.KEYGUARD);
136         // WHEN the plugin is connected
137         mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
138         // THEN the big clock container is visible and it is the parent of the
139         // big clock view.
140         assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE);
141         assertThat(mBigClock.getParent()).isEqualTo(mBigClockContainer);
142     }
143 
144     @Test
onPluginConnected_nullView()145     public void onPluginConnected_nullView() {
146         ClockPlugin plugin = mock(ClockPlugin.class);
147         mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
148         verify(mClockView, never()).setVisibility(GONE);
149     }
150 
151     @Test
onPluginConnected_showSecondPluginClock()152     public void onPluginConnected_showSecondPluginClock() {
153         // GIVEN a plugin has already connected
154         ClockPlugin plugin1 = mock(ClockPlugin.class);
155         when(plugin1.getView()).thenReturn(new TextClock(getContext()));
156         mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin1);
157         // WHEN a second plugin is connected
158         ClockPlugin plugin2 = mock(ClockPlugin.class);
159         when(plugin2.getView()).thenReturn(new TextClock(getContext()));
160         mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin2);
161         // THEN only the view from the second plugin should be a child of KeyguardClockSwitch.
162         assertThat(plugin2.getView().getParent()).isEqualTo(mClockContainer);
163         assertThat(plugin1.getView().getParent()).isNull();
164     }
165 
166     @Test
onPluginConnected_darkAmountInitialized()167     public void onPluginConnected_darkAmountInitialized() {
168         // GIVEN that the dark amount has already been set
169         mKeyguardClockSwitch.setDarkAmount(0.5f);
170         // WHEN a plugin is connected
171         ClockPlugin plugin = mock(ClockPlugin.class);
172         mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
173         // THEN dark amount should be initalized on the plugin.
174         verify(plugin).setDarkAmount(0.5f);
175     }
176 
177     @Test
onPluginDisconnected_showDefaultClock()178     public void onPluginDisconnected_showDefaultClock() {
179         ClockPlugin plugin = mock(ClockPlugin.class);
180         TextClock pluginView = new TextClock(getContext());
181         when(plugin.getView()).thenReturn(pluginView);
182         mClockView.setVisibility(GONE);
183 
184         mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
185         mKeyguardClockSwitch.getClockChangedListener().onClockChanged(null);
186 
187         verify(mClockView).setVisibility(VISIBLE);
188         assertThat(plugin.getView().getParent()).isNull();
189     }
190 
191     @Test
onPluginDisconnected_hidePluginBigClock()192     public void onPluginDisconnected_hidePluginBigClock() {
193         // GIVEN that the big clock container is visible
194         FrameLayout bigClockContainer = new FrameLayout(getContext());
195         bigClockContainer.setVisibility(VISIBLE);
196         mKeyguardClockSwitch.setBigClockContainer(bigClockContainer);
197         // AND the plugin returns a view for the big clock
198         ClockPlugin plugin = mock(ClockPlugin.class);
199         TextClock pluginView = new TextClock(getContext());
200         when(plugin.getBigClockView()).thenReturn(pluginView);
201         // AND in the keyguard state
202         mStateListener.onStateChanged(StatusBarState.KEYGUARD);
203         // WHEN the plugin is connected and then disconnected
204         mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
205         mKeyguardClockSwitch.getClockChangedListener().onClockChanged(null);
206         // THEN the big lock container is GONE and the big clock view doesn't have
207         // a parent.
208         assertThat(bigClockContainer.getVisibility()).isEqualTo(GONE);
209         assertThat(pluginView.getParent()).isNull();
210     }
211 
212     @Test
onPluginDisconnected_nullView()213     public void onPluginDisconnected_nullView() {
214         ClockPlugin plugin = mock(ClockPlugin.class);
215         mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
216         mKeyguardClockSwitch.getClockChangedListener().onClockChanged(null);
217         verify(mClockView, never()).setVisibility(GONE);
218     }
219 
220     @Test
onPluginDisconnected_secondOfTwoDisconnected()221     public void onPluginDisconnected_secondOfTwoDisconnected() {
222         // GIVEN two plugins are connected
223         ClockPlugin plugin1 = mock(ClockPlugin.class);
224         when(plugin1.getView()).thenReturn(new TextClock(getContext()));
225         ClockManager.ClockChangedListener listener = mKeyguardClockSwitch.getClockChangedListener();
226         listener.onClockChanged(plugin1);
227         ClockPlugin plugin2 = mock(ClockPlugin.class);
228         when(plugin2.getView()).thenReturn(new TextClock(getContext()));
229         listener.onClockChanged(plugin2);
230         // WHEN the second plugin is disconnected
231         listener.onClockChanged(null);
232         // THEN the default clock should be shown.
233         verify(mClockView).setVisibility(VISIBLE);
234         assertThat(plugin1.getView().getParent()).isNull();
235         assertThat(plugin2.getView().getParent()).isNull();
236     }
237 
238     @Test
onPluginDisconnected_onDestroyView()239     public void onPluginDisconnected_onDestroyView() {
240         // GIVEN a plugin is connected
241         ClockPlugin clockPlugin = mock(ClockPlugin.class);
242         when(clockPlugin.getView()).thenReturn(new TextClock(getContext()));
243         ClockManager.ClockChangedListener listener = mKeyguardClockSwitch.getClockChangedListener();
244         listener.onClockChanged(clockPlugin);
245         // WHEN the plugin is disconnected
246         listener.onClockChanged(null);
247         // THEN onDestroyView is called on the plugin
248         verify(clockPlugin).onDestroyView();
249     }
250 
251     @Test
setTextColor_defaultClockSetTextColor()252     public void setTextColor_defaultClockSetTextColor() {
253         mKeyguardClockSwitch.setTextColor(Color.YELLOW);
254 
255         verify(mClockView).setTextColor(Color.YELLOW);
256     }
257 
258     @Test
setTextColor_pluginClockSetTextColor()259     public void setTextColor_pluginClockSetTextColor() {
260         ClockPlugin plugin = mock(ClockPlugin.class);
261         TextClock pluginView = new TextClock(getContext());
262         when(plugin.getView()).thenReturn(pluginView);
263         mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
264 
265         mKeyguardClockSwitch.setTextColor(Color.WHITE);
266 
267         verify(plugin).setTextColor(Color.WHITE);
268     }
269 
270     @Test
setStyle_defaultClockSetStyle()271     public void setStyle_defaultClockSetStyle() {
272         TextPaint paint = mock(TextPaint.class);
273         Style style = mock(Style.class);
274         doReturn(paint).when(mClockView).getPaint();
275 
276         mKeyguardClockSwitch.setStyle(style);
277 
278         verify(paint).setStyle(style);
279     }
280 
281     @Test
setStyle_pluginClockSetStyle()282     public void setStyle_pluginClockSetStyle() {
283         ClockPlugin plugin = mock(ClockPlugin.class);
284         TextClock pluginView = new TextClock(getContext());
285         when(plugin.getView()).thenReturn(pluginView);
286         Style style = mock(Style.class);
287         mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
288 
289         mKeyguardClockSwitch.setStyle(style);
290 
291         verify(plugin).setStyle(style);
292     }
293 
294     @Test
onStateChanged_GoneInShade()295     public void onStateChanged_GoneInShade() {
296         // GIVEN that the big clock container is visible
297         mBigClockContainer.setVisibility(View.VISIBLE);
298         mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
299         // WHEN transitioned to SHADE state
300         mStateListener.onStateChanged(StatusBarState.SHADE);
301         // THEN the container is gone.
302         assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.GONE);
303     }
304 
305     @Test
onStateChanged_VisibleInKeyguard()306     public void onStateChanged_VisibleInKeyguard() {
307         // GIVEN that the big clock container is gone
308         mBigClockContainer.setVisibility(View.GONE);
309         mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
310         // AND GIVEN that a plugin is active.
311         ClockPlugin plugin = mock(ClockPlugin.class);
312         when(plugin.getBigClockView()).thenReturn(mBigClock);
313         mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
314         // WHEN transitioned to KEYGUARD state
315         mStateListener.onStateChanged(StatusBarState.KEYGUARD);
316         // THEN the container is visible.
317         assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE);
318     }
319 
320     @Test
setBigClockContainer_visible()321     public void setBigClockContainer_visible() {
322         // GIVEN that the big clock container is visible
323         mBigClockContainer.setVisibility(View.VISIBLE);
324         // AND GIVEN that a plugin is active.
325         ClockPlugin plugin = mock(ClockPlugin.class);
326         when(plugin.getBigClockView()).thenReturn(mBigClock);
327         mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
328         // AND in the keyguard state
329         mStateListener.onStateChanged(StatusBarState.KEYGUARD);
330         // WHEN the container is associated with the clock switch
331         mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
332         // THEN the container remains visible.
333         assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE);
334     }
335 
336     @Test
setBigClockContainer_gone()337     public void setBigClockContainer_gone() {
338         // GIVEN that the big clock container is gone
339         mBigClockContainer.setVisibility(View.GONE);
340         // AND GIVEN that a plugin is active.
341         ClockPlugin plugin = mock(ClockPlugin.class);
342         when(plugin.getBigClockView()).thenReturn(mBigClock);
343         mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
344         // AND in the keyguard state
345         mStateListener.onStateChanged(StatusBarState.KEYGUARD);
346         // WHEN the container is associated with the clock switch
347         mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
348         // THEN the container is made visible.
349         assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE);
350     }
351 }
352