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.INVISIBLE;
20 import static android.view.View.VISIBLE;
21 
22 import static com.android.keyguard.KeyguardClockSwitch.LARGE;
23 import static com.android.keyguard.KeyguardClockSwitch.SMALL;
24 
25 import static com.google.common.truth.Truth.assertThat;
26 
27 import static junit.framework.TestCase.assertEquals;
28 
29 import static org.mockito.Mockito.mock;
30 import static org.mockito.Mockito.when;
31 
32 import android.content.Context;
33 import android.test.suitebuilder.annotation.SmallTest;
34 import android.testing.AndroidTestingRunner;
35 import android.testing.TestableLooper.RunWithLooper;
36 import android.util.AttributeSet;
37 import android.view.LayoutInflater;
38 import android.view.View;
39 import android.view.ViewGroup;
40 import android.widget.FrameLayout;
41 import android.widget.TextView;
42 
43 import com.android.systemui.R;
44 import com.android.systemui.SysuiTestCase;
45 import com.android.systemui.plugins.ClockController;
46 import com.android.systemui.plugins.ClockFaceController;
47 import com.android.systemui.statusbar.StatusBarState;
48 
49 import org.junit.Before;
50 import org.junit.Test;
51 import org.junit.runner.RunWith;
52 import org.mockito.Mock;
53 import org.mockito.MockitoAnnotations;
54 
55 @SmallTest
56 @RunWith(AndroidTestingRunner.class)
57 // Need to run on the main thread because KeyguardSliceView$Row init checks for
58 // the main thread before acquiring a wake lock. This class is constructed when
59 // the keyguard_clock_switch layout is inflated.
60 @RunWithLooper(setAsMainLooper = true)
61 public class KeyguardClockSwitchTest extends SysuiTestCase {
62     @Mock
63     ViewGroup mMockKeyguardSliceView;
64 
65     @Mock
66     ClockController mClock;
67 
68     @Mock
69     ClockFaceController mSmallClock;
70 
71     @Mock
72     ClockFaceController mLargeClock;
73 
74     private FrameLayout mSmallClockFrame;
75     private FrameLayout mLargeClockFrame;
76     private KeyguardStatusAreaView mStatusArea;
77 
78     KeyguardClockSwitch mKeyguardClockSwitch;
79 
80     @Before
setUp()81     public void setUp() {
82         MockitoAnnotations.initMocks(this);
83         when(mMockKeyguardSliceView.getContext()).thenReturn(mContext);
84         when(mMockKeyguardSliceView.findViewById(R.id.keyguard_status_area))
85                 .thenReturn(mMockKeyguardSliceView);
86 
87         when(mClock.getSmallClock()).thenReturn(mSmallClock);
88         when(mClock.getLargeClock()).thenReturn(mLargeClock);
89 
90         when(mSmallClock.getView()).thenReturn(new TextView(getContext()));
91         when(mLargeClock.getView()).thenReturn(new TextView(getContext()));
92 
93         LayoutInflater layoutInflater = LayoutInflater.from(getContext());
94         layoutInflater.setPrivateFactory(new LayoutInflater.Factory2() {
95 
96             @Override
97             public View onCreateView(View parent, String name, Context context,
98                     AttributeSet attrs) {
99                 return onCreateView(name, context, attrs);
100             }
101 
102             @Override
103             public View onCreateView(String name, Context context, AttributeSet attrs) {
104                 if ("com.android.keyguard.KeyguardSliceView".equals(name)) {
105                     return mMockKeyguardSliceView;
106                 }
107                 return null;
108             }
109         });
110         mKeyguardClockSwitch =
111                 (KeyguardClockSwitch) layoutInflater.inflate(R.layout.keyguard_clock_switch, null);
112         mSmallClockFrame = mKeyguardClockSwitch.findViewById(R.id.lockscreen_clock_view);
113         mLargeClockFrame = mKeyguardClockSwitch.findViewById(R.id.lockscreen_clock_view_large);
114         mStatusArea = mKeyguardClockSwitch.findViewById(R.id.keyguard_status_area);
115         mKeyguardClockSwitch.mChildrenAreLaidOut = true;
116     }
117 
118     @Test
noPluginConnected_showNothing()119     public void noPluginConnected_showNothing() {
120         mKeyguardClockSwitch.setClock(null, StatusBarState.KEYGUARD);
121         assertEquals(mLargeClockFrame.getChildCount(), 0);
122         assertEquals(mSmallClockFrame.getChildCount(), 0);
123     }
124 
125     @Test
pluginConnectedThenDisconnected_showNothing()126     public void pluginConnectedThenDisconnected_showNothing() {
127         mKeyguardClockSwitch.setClock(mClock, StatusBarState.KEYGUARD);
128         assertEquals(mLargeClockFrame.getChildCount(), 1);
129         assertEquals(mSmallClockFrame.getChildCount(), 1);
130 
131         mKeyguardClockSwitch.setClock(null, StatusBarState.KEYGUARD);
132         assertEquals(mLargeClockFrame.getChildCount(), 0);
133         assertEquals(mSmallClockFrame.getChildCount(), 0);
134     }
135 
136     @Test
onPluginConnected_showClock()137     public void onPluginConnected_showClock() {
138         mKeyguardClockSwitch.setClock(mClock, StatusBarState.KEYGUARD);
139 
140         assertEquals(mClock.getSmallClock().getView().getParent(), mSmallClockFrame);
141         assertEquals(mClock.getLargeClock().getView().getParent(), mLargeClockFrame);
142     }
143 
144     @Test
onPluginConnected_showSecondPluginClock()145     public void onPluginConnected_showSecondPluginClock() {
146         // GIVEN a plugin has already connected
147         ClockController otherClock = mock(ClockController.class);
148         ClockFaceController smallClock = mock(ClockFaceController.class);
149         ClockFaceController largeClock = mock(ClockFaceController.class);
150         when(otherClock.getSmallClock()).thenReturn(smallClock);
151         when(otherClock.getLargeClock()).thenReturn(largeClock);
152         when(smallClock.getView()).thenReturn(new TextView(getContext()));
153         when(largeClock.getView()).thenReturn(new TextView(getContext()));
154         mKeyguardClockSwitch.setClock(mClock, StatusBarState.KEYGUARD);
155         mKeyguardClockSwitch.setClock(otherClock, StatusBarState.KEYGUARD);
156 
157         // THEN only the view from the second plugin should be a child of KeyguardClockSwitch.
158         assertThat(otherClock.getSmallClock().getView().getParent()).isEqualTo(mSmallClockFrame);
159         assertThat(otherClock.getLargeClock().getView().getParent()).isEqualTo(mLargeClockFrame);
160         assertThat(mClock.getSmallClock().getView().getParent()).isNull();
161         assertThat(mClock.getLargeClock().getView().getParent()).isNull();
162     }
163 
164     @Test
onPluginDisconnected_secondOfTwoDisconnected()165     public void onPluginDisconnected_secondOfTwoDisconnected() {
166         // GIVEN two plugins are connected
167         ClockController otherClock = mock(ClockController.class);
168         ClockFaceController smallClock = mock(ClockFaceController.class);
169         ClockFaceController largeClock = mock(ClockFaceController.class);
170         when(otherClock.getSmallClock()).thenReturn(smallClock);
171         when(otherClock.getLargeClock()).thenReturn(largeClock);
172         when(smallClock.getView()).thenReturn(new TextView(getContext()));
173         when(largeClock.getView()).thenReturn(new TextView(getContext()));
174         mKeyguardClockSwitch.setClock(otherClock, StatusBarState.KEYGUARD);
175         mKeyguardClockSwitch.setClock(mClock, StatusBarState.KEYGUARD);
176         // WHEN the second plugin is disconnected
177         mKeyguardClockSwitch.setClock(null, StatusBarState.KEYGUARD);
178         // THEN nothing should be shown
179         assertThat(otherClock.getSmallClock().getView().getParent()).isNull();
180         assertThat(otherClock.getLargeClock().getView().getParent()).isNull();
181         assertThat(mClock.getSmallClock().getView().getParent()).isNull();
182         assertThat(mClock.getLargeClock().getView().getParent()).isNull();
183     }
184 
185     @Test
switchingToBigClockWithAnimation_makesSmallClockDisappear()186     public void switchingToBigClockWithAnimation_makesSmallClockDisappear() {
187         mKeyguardClockSwitch.switchToClock(LARGE, /* animate */ true);
188 
189         mKeyguardClockSwitch.mClockInAnim.end();
190         mKeyguardClockSwitch.mClockOutAnim.end();
191         mKeyguardClockSwitch.mStatusAreaAnim.end();
192 
193         assertThat(mLargeClockFrame.getAlpha()).isEqualTo(1);
194         assertThat(mLargeClockFrame.getVisibility()).isEqualTo(VISIBLE);
195         assertThat(mSmallClockFrame.getAlpha()).isEqualTo(0);
196         assertThat(mSmallClockFrame.getVisibility()).isEqualTo(INVISIBLE);
197     }
198 
199     @Test
switchingToBigClockNoAnimation_makesSmallClockDisappear()200     public void switchingToBigClockNoAnimation_makesSmallClockDisappear() {
201         mKeyguardClockSwitch.switchToClock(LARGE, /* animate */ false);
202 
203         assertThat(mLargeClockFrame.getAlpha()).isEqualTo(1);
204         assertThat(mLargeClockFrame.getVisibility()).isEqualTo(VISIBLE);
205         assertThat(mSmallClockFrame.getAlpha()).isEqualTo(0);
206         assertThat(mSmallClockFrame.getVisibility()).isEqualTo(INVISIBLE);
207     }
208 
209     @Test
switchingToSmallClockWithAnimation_makesBigClockDisappear()210     public void switchingToSmallClockWithAnimation_makesBigClockDisappear() {
211         mKeyguardClockSwitch.switchToClock(SMALL, /* animate */ true);
212 
213         mKeyguardClockSwitch.mClockInAnim.end();
214         mKeyguardClockSwitch.mClockOutAnim.end();
215         mKeyguardClockSwitch.mStatusAreaAnim.end();
216 
217         assertThat(mSmallClockFrame.getAlpha()).isEqualTo(1);
218         assertThat(mSmallClockFrame.getVisibility()).isEqualTo(VISIBLE);
219         // only big clock is removed at switch
220         assertThat(mLargeClockFrame.getParent()).isNull();
221         assertThat(mLargeClockFrame.getAlpha()).isEqualTo(0);
222         assertThat(mLargeClockFrame.getVisibility()).isEqualTo(INVISIBLE);
223     }
224 
225     @Test
switchingToSmallClockNoAnimation_makesBigClockDisappear()226     public void switchingToSmallClockNoAnimation_makesBigClockDisappear() {
227         mKeyguardClockSwitch.switchToClock(SMALL, false);
228 
229         assertThat(mSmallClockFrame.getAlpha()).isEqualTo(1);
230         assertThat(mSmallClockFrame.getVisibility()).isEqualTo(VISIBLE);
231         // only big clock is removed at switch
232         assertThat(mLargeClockFrame.getParent()).isNull();
233         assertThat(mLargeClockFrame.getAlpha()).isEqualTo(0);
234         assertThat(mLargeClockFrame.getVisibility()).isEqualTo(INVISIBLE);
235     }
236 
237     @Test
switchingToSmallClockAnimation_resetsStatusArea()238     public void switchingToSmallClockAnimation_resetsStatusArea() {
239         mKeyguardClockSwitch.switchToClock(SMALL, true);
240 
241         mKeyguardClockSwitch.mClockInAnim.end();
242         mKeyguardClockSwitch.mClockOutAnim.end();
243         mKeyguardClockSwitch.mStatusAreaAnim.end();
244 
245         assertThat(mStatusArea.getTranslationX()).isEqualTo(0);
246         assertThat(mStatusArea.getTranslationY()).isEqualTo(0);
247         assertThat(mStatusArea.getScaleX()).isEqualTo(1);
248         assertThat(mStatusArea.getScaleY()).isEqualTo(1);
249     }
250 
251     @Test
switchingToSmallClockNoAnimation_resetsStatusArea()252     public void switchingToSmallClockNoAnimation_resetsStatusArea() {
253         mKeyguardClockSwitch.switchToClock(SMALL, false);
254 
255         assertThat(mStatusArea.getTranslationX()).isEqualTo(0);
256         assertThat(mStatusArea.getTranslationY()).isEqualTo(0);
257         assertThat(mStatusArea.getScaleX()).isEqualTo(1);
258         assertThat(mStatusArea.getScaleY()).isEqualTo(1);
259     }
260 
261 
262     @Test
switchingToBigClock_returnsTrueOnlyWhenItWasNotVisibleBefore()263     public void switchingToBigClock_returnsTrueOnlyWhenItWasNotVisibleBefore() {
264         assertThat(mKeyguardClockSwitch.switchToClock(LARGE, /* animate */ true)).isTrue();
265         assertThat(mKeyguardClockSwitch.switchToClock(LARGE, /* animate */ true)).isFalse();
266     }
267 }
268