1 /*
2  * Copyright (C) 2020 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 org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertNull;
21 import static org.mockito.ArgumentMatchers.any;
22 import static org.mockito.ArgumentMatchers.anyBoolean;
23 import static org.mockito.ArgumentMatchers.eq;
24 import static org.mockito.Mockito.never;
25 import static org.mockito.Mockito.reset;
26 import static org.mockito.Mockito.times;
27 import static org.mockito.Mockito.verify;
28 import static org.mockito.Mockito.when;
29 
30 import android.database.ContentObserver;
31 import android.os.UserHandle;
32 import android.provider.Settings;
33 import android.testing.AndroidTestingRunner;
34 import android.view.View;
35 
36 import androidx.test.filters.SmallTest;
37 
38 import com.android.systemui.plugins.ClockFaceConfig;
39 import com.android.systemui.plugins.ClockTickRate;
40 import com.android.systemui.shared.clocks.ClockRegistry;
41 import com.android.systemui.statusbar.StatusBarState;
42 
43 import org.junit.Test;
44 import org.junit.runner.RunWith;
45 import org.mockito.ArgumentCaptor;
46 import org.mockito.verification.VerificationMode;
47 
48 @SmallTest
49 @RunWith(AndroidTestingRunner.class)
50 public class KeyguardClockSwitchControllerTest extends KeyguardClockSwitchControllerBaseTest {
51     @Test
testInit_viewAlreadyAttached()52     public void testInit_viewAlreadyAttached() {
53         mController.init();
54 
55         verifyAttachment(times(1));
56     }
57 
58     @Test
testInit_viewNotYetAttached()59     public void testInit_viewNotYetAttached() {
60         ArgumentCaptor<View.OnAttachStateChangeListener> listenerArgumentCaptor =
61                 ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
62 
63         when(mView.isAttachedToWindow()).thenReturn(false);
64         mController.init();
65         verify(mView).addOnAttachStateChangeListener(listenerArgumentCaptor.capture());
66 
67         verifyAttachment(never());
68 
69         listenerArgumentCaptor.getValue().onViewAttachedToWindow(mView);
70 
71         verifyAttachment(times(1));
72     }
73 
74     @Test
testInitSubControllers()75     public void testInitSubControllers() {
76         mController.init();
77         verify(mKeyguardSliceViewController).init();
78     }
79 
80     @Test
testInit_viewDetached()81     public void testInit_viewDetached() {
82         ArgumentCaptor<View.OnAttachStateChangeListener> listenerArgumentCaptor =
83                 ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
84         mController.init();
85         verify(mView).addOnAttachStateChangeListener(listenerArgumentCaptor.capture());
86 
87         verifyAttachment(times(1));
88 
89         listenerArgumentCaptor.getValue().onViewDetachedFromWindow(mView);
90         verify(mClockEventController).unregisterListeners();
91     }
92 
93     @Test
testPluginPassesStatusBarState()94     public void testPluginPassesStatusBarState() {
95         ArgumentCaptor<ClockRegistry.ClockChangeListener> listenerArgumentCaptor =
96                 ArgumentCaptor.forClass(ClockRegistry.ClockChangeListener.class);
97 
98         mController.init();
99         verify(mClockRegistry).registerClockChangeListener(listenerArgumentCaptor.capture());
100 
101         listenerArgumentCaptor.getValue().onCurrentClockChanged();
102         verify(mView, times(2)).setClock(mClockController, StatusBarState.SHADE);
103         verify(mClockEventController, times(2)).setClock(mClockController);
104     }
105 
106     @Test
testSmartspaceEnabledRemovesKeyguardStatusArea()107     public void testSmartspaceEnabledRemovesKeyguardStatusArea() {
108         when(mSmartspaceController.isEnabled()).thenReturn(true);
109         mController.init();
110 
111         assertEquals(View.GONE, mSliceView.getVisibility());
112     }
113 
114     @Test
onLocaleListChangedRebuildsSmartspaceView()115     public void onLocaleListChangedRebuildsSmartspaceView() {
116         when(mSmartspaceController.isEnabled()).thenReturn(true);
117         mController.init();
118 
119         mController.onLocaleListChanged();
120         // Should be called once on initial setup, then once again for locale change
121         verify(mSmartspaceController, times(2)).buildAndConnectView(mView);
122     }
123 
124     @Test
onLocaleListChanged_rebuildsSmartspaceViews_whenDecouplingEnabled()125     public void onLocaleListChanged_rebuildsSmartspaceViews_whenDecouplingEnabled() {
126         when(mSmartspaceController.isEnabled()).thenReturn(true);
127         when(mSmartspaceController.isDateWeatherDecoupled()).thenReturn(true);
128         mController.init();
129 
130         mController.onLocaleListChanged();
131         // Should be called once on initial setup, then once again for locale change
132         verify(mSmartspaceController, times(2)).buildAndConnectDateView(mView);
133         verify(mSmartspaceController, times(2)).buildAndConnectWeatherView(mView);
134         verify(mSmartspaceController, times(2)).buildAndConnectView(mView);
135     }
136 
137     @Test
testSmartspaceDisabledShowsKeyguardStatusArea()138     public void testSmartspaceDisabledShowsKeyguardStatusArea() {
139         when(mSmartspaceController.isEnabled()).thenReturn(false);
140         mController.init();
141 
142         assertEquals(View.VISIBLE, mSliceView.getVisibility());
143     }
144 
145     @Test
testRefresh()146     public void testRefresh() {
147         mController.refresh();
148 
149         verify(mSmartspaceController).requestSmartspaceUpdate();
150     }
151 
152     @Test
testChangeToDoubleLineClockSetsSmallClock()153     public void testChangeToDoubleLineClockSetsSmallClock() {
154         when(mSecureSettings.getIntForUser(Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, 1,
155                 UserHandle.USER_CURRENT))
156                 .thenReturn(0);
157         ArgumentCaptor<ContentObserver> observerCaptor =
158                 ArgumentCaptor.forClass(ContentObserver.class);
159         mController.init();
160         verify(mSecureSettings).registerContentObserverForUser(
161                 eq(Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK),
162                     anyBoolean(), observerCaptor.capture(), eq(UserHandle.USER_ALL));
163         ContentObserver observer = observerCaptor.getValue();
164         mExecutor.runAllReady();
165 
166         // When a settings change has occurred to the small clock, make sure the view is adjusted
167         reset(mView);
168         observer.onChange(true);
169         mExecutor.runAllReady();
170         verify(mView).switchToClock(KeyguardClockSwitch.SMALL, /* animate */ true);
171     }
172 
173     @Test
testGetClock_ForwardsToClock()174     public void testGetClock_ForwardsToClock() {
175         assertEquals(mClockController, mController.getClock());
176     }
177 
178     @Test
testGetLargeClockBottom_returnsExpectedValue()179     public void testGetLargeClockBottom_returnsExpectedValue() {
180         when(mLargeClockFrame.getVisibility()).thenReturn(View.VISIBLE);
181         when(mLargeClockFrame.getHeight()).thenReturn(100);
182         when(mSmallClockFrame.getHeight()).thenReturn(50);
183         when(mLargeClockView.getHeight()).thenReturn(40);
184         when(mSmallClockView.getHeight()).thenReturn(20);
185         mController.init();
186 
187         assertEquals(170, mController.getClockBottom(1000));
188     }
189 
190     @Test
testGetSmallLargeClockBottom_returnsExpectedValue()191     public void testGetSmallLargeClockBottom_returnsExpectedValue() {
192         when(mLargeClockFrame.getVisibility()).thenReturn(View.GONE);
193         when(mLargeClockFrame.getHeight()).thenReturn(100);
194         when(mSmallClockFrame.getHeight()).thenReturn(50);
195         when(mLargeClockView.getHeight()).thenReturn(40);
196         when(mSmallClockView.getHeight()).thenReturn(20);
197         mController.init();
198 
199         assertEquals(1120, mController.getClockBottom(1000));
200     }
201 
202     @Test
testGetClockBottom_nullClock_returnsZero()203     public void testGetClockBottom_nullClock_returnsZero() {
204         when(mClockEventController.getClock()).thenReturn(null);
205         assertEquals(0, mController.getClockBottom(10));
206     }
207 
208     @Test
testChangeLockscreenWeatherEnabledSetsWeatherViewVisible()209     public void testChangeLockscreenWeatherEnabledSetsWeatherViewVisible() {
210         when(mSmartspaceController.isWeatherEnabled()).thenReturn(true);
211         ArgumentCaptor<ContentObserver> observerCaptor =
212                 ArgumentCaptor.forClass(ContentObserver.class);
213         mController.init();
214         verify(mSecureSettings).registerContentObserverForUser(
215                 eq(Settings.Secure.LOCK_SCREEN_WEATHER_ENABLED), anyBoolean(),
216                     observerCaptor.capture(), eq(UserHandle.USER_ALL));
217         ContentObserver observer = observerCaptor.getValue();
218         mExecutor.runAllReady();
219         // When a settings change has occurred, check that view is visible.
220         observer.onChange(true);
221         mExecutor.runAllReady();
222         assertEquals(View.VISIBLE, mFakeWeatherView.getVisibility());
223     }
224 
225     @Test
testChangeClockDateWeatherEnabled_SetsDateWeatherViewVisibility()226     public void testChangeClockDateWeatherEnabled_SetsDateWeatherViewVisibility() {
227         ArgumentCaptor<ClockRegistry.ClockChangeListener> listenerArgumentCaptor =
228                 ArgumentCaptor.forClass(ClockRegistry.ClockChangeListener.class);
229         when(mSmartspaceController.isEnabled()).thenReturn(true);
230         when(mSmartspaceController.isDateWeatherDecoupled()).thenReturn(true);
231         when(mSmartspaceController.isWeatherEnabled()).thenReturn(true);
232         mController.init();
233         mExecutor.runAllReady();
234         assertEquals(View.VISIBLE, mFakeDateView.getVisibility());
235 
236         when(mSmallClockController.getConfig())
237                 .thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, true, false));
238         when(mLargeClockController.getConfig())
239                 .thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, true, false));
240         verify(mClockRegistry).registerClockChangeListener(listenerArgumentCaptor.capture());
241         listenerArgumentCaptor.getValue().onCurrentClockChanged();
242 
243         mExecutor.runAllReady();
244         assertEquals(View.INVISIBLE, mFakeDateView.getVisibility());
245     }
246 
247     @Test
testGetClock_nullClock_returnsNull()248     public void testGetClock_nullClock_returnsNull() {
249         when(mClockEventController.getClock()).thenReturn(null);
250         assertNull(mController.getClock());
251     }
252 
verifyAttachment(VerificationMode times)253     private void verifyAttachment(VerificationMode times) {
254         verify(mClockRegistry, times).registerClockChangeListener(
255                 any(ClockRegistry.ClockChangeListener.class));
256         verify(mClockEventController, times).registerListeners(mView);
257     }
258 
259     @Test
testSplitShadeEnabledSetToSmartspaceController()260     public void testSplitShadeEnabledSetToSmartspaceController() {
261         mController.setSplitShadeEnabled(true);
262         verify(mSmartspaceController, times(1)).setSplitShadeEnabled(true);
263         verify(mSmartspaceController, times(0)).setSplitShadeEnabled(false);
264     }
265 
266     @Test
testSplitShadeDisabledSetToSmartspaceController()267     public void testSplitShadeDisabledSetToSmartspaceController() {
268         mController.setSplitShadeEnabled(false);
269         verify(mSmartspaceController, times(1)).setSplitShadeEnabled(false);
270         verify(mSmartspaceController, times(0)).setSplitShadeEnabled(true);
271     }
272 }
273