blob: 3330d1e6d0a81bda8637feae0803a2eb375026b1 [file] [log] [blame]
Robert Snoebergerb300a4e2019-02-13 20:13:53 +00001/*
2 * Copyright (C) 2019 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 */
16package com.android.keyguard.clock;
17
18import static com.google.common.truth.Truth.assertThat;
19
Robert Snoeberger71e50792019-02-15 15:48:01 -050020import static org.mockito.ArgumentMatchers.any;
Robert Snoeberger372e13f2019-04-08 17:07:14 -040021import static org.mockito.ArgumentMatchers.anyInt;
Robert Snoebergerd8445ea2019-03-27 10:41:23 -040022import static org.mockito.Mockito.reset;
23import static org.mockito.Mockito.verify;
Robert Snoeberger71e50792019-02-15 15:48:01 -050024import static org.mockito.Mockito.when;
25
26import android.content.ContentResolver;
27import android.database.ContentObserver;
Robert Snoeberger372e13f2019-04-08 17:07:14 -040028import android.net.Uri;
Robert Snoebergerb300a4e2019-02-13 20:13:53 +000029import android.test.suitebuilder.annotation.SmallTest;
30import android.testing.AndroidTestingRunner;
Robert Snoebergerb300a4e2019-02-13 20:13:53 +000031import android.testing.TestableLooper.RunWithLooper;
Robert Snoeberger71e50792019-02-15 15:48:01 -050032import android.view.LayoutInflater;
Robert Snoebergerb300a4e2019-02-13 20:13:53 +000033
Robert Snoebergerbe2a1882019-04-10 13:48:02 -040034import androidx.lifecycle.MutableLiveData;
35
Robert Snoebergerb300a4e2019-02-13 20:13:53 +000036import com.android.systemui.SysuiTestCase;
Robert Snoeberger71e50792019-02-15 15:48:01 -050037import com.android.systemui.colorextraction.SysuiColorExtractor;
Robert Snoebergerb300a4e2019-02-13 20:13:53 +000038import com.android.systemui.dock.DockManager;
39import com.android.systemui.dock.DockManagerFake;
Robert Snoebergerd8445ea2019-03-27 10:41:23 -040040import com.android.systemui.plugins.ClockPlugin;
Robert Snoebergerbe2a1882019-04-10 13:48:02 -040041import com.android.systemui.settings.CurrentUserObservable;
Robert Snoeberger9ad03f42019-02-28 14:47:49 -050042import com.android.systemui.shared.plugins.PluginManager;
Robert Snoeberger71e50792019-02-15 15:48:01 -050043import com.android.systemui.util.InjectionInflationController;
Robert Snoebergerb300a4e2019-02-13 20:13:53 +000044
45import org.junit.After;
46import org.junit.Before;
47import org.junit.Test;
48import org.junit.runner.RunWith;
Robert Snoebergerd8445ea2019-03-27 10:41:23 -040049import org.mockito.ArgumentCaptor;
Robert Snoebergerb300a4e2019-02-13 20:13:53 +000050import org.mockito.Mock;
51import org.mockito.MockitoAnnotations;
52
53@SmallTest
54@RunWith(AndroidTestingRunner.class)
Robert Snoebergerbe2a1882019-04-10 13:48:02 -040055// Need to run tests on main looper because LiveData operations such as setData, observe,
56// removeObserver cannot be invoked on a background thread.
57@RunWithLooper(setAsMainLooper = true)
Robert Snoebergerb300a4e2019-02-13 20:13:53 +000058public final class ClockManagerTest extends SysuiTestCase {
59
Robert Snoeberger71e50792019-02-15 15:48:01 -050060 private static final String BUBBLE_CLOCK = BubbleClockController.class.getName();
61 private static final Class<?> BUBBLE_CLOCK_CLASS = BubbleClockController.class;
Robert Snoebergerbe2a1882019-04-10 13:48:02 -040062 private static final int MAIN_USER_ID = 0;
63 private static final int SECONDARY_USER_ID = 11;
Robert Snoeberger372e13f2019-04-08 17:07:14 -040064 private static final Uri SETTINGS_URI = null;
Robert Snoeberger71e50792019-02-15 15:48:01 -050065
Robert Snoebergerb300a4e2019-02-13 20:13:53 +000066 private ClockManager mClockManager;
Robert Snoeberger71e50792019-02-15 15:48:01 -050067 private ContentObserver mContentObserver;
Robert Snoebergerb300a4e2019-02-13 20:13:53 +000068 private DockManagerFake mFakeDockManager;
Robert Snoebergerbe2a1882019-04-10 13:48:02 -040069 private MutableLiveData<Integer> mCurrentUser;
Robert Snoeberger71e50792019-02-15 15:48:01 -050070 @Mock InjectionInflationController mMockInjectionInflationController;
Robert Snoeberger9ad03f42019-02-28 14:47:49 -050071 @Mock PluginManager mMockPluginManager;
Robert Snoeberger71e50792019-02-15 15:48:01 -050072 @Mock SysuiColorExtractor mMockColorExtractor;
73 @Mock ContentResolver mMockContentResolver;
Robert Snoebergerbe2a1882019-04-10 13:48:02 -040074 @Mock CurrentUserObservable mMockCurrentUserObserable;
Robert Snoeberger71e50792019-02-15 15:48:01 -050075 @Mock SettingsWrapper mMockSettingsWrapper;
Robert Snoebergerd8445ea2019-03-27 10:41:23 -040076 @Mock ClockManager.ClockChangedListener mMockListener1;
77 @Mock ClockManager.ClockChangedListener mMockListener2;
Robert Snoebergerb300a4e2019-02-13 20:13:53 +000078
79 @Before
80 public void setUp() {
81 MockitoAnnotations.initMocks(this);
Robert Snoeberger71e50792019-02-15 15:48:01 -050082
83 LayoutInflater inflater = LayoutInflater.from(getContext());
84 when(mMockInjectionInflationController.injectable(any())).thenReturn(inflater);
85
Robert Snoebergerb300a4e2019-02-13 20:13:53 +000086 mFakeDockManager = new DockManagerFake();
Robert Snoeberger3f4650c2019-03-25 14:41:42 -040087
Robert Snoebergerbe2a1882019-04-10 13:48:02 -040088 mCurrentUser = new MutableLiveData<>();
89 mCurrentUser.setValue(MAIN_USER_ID);
90 when(mMockCurrentUserObserable.getCurrentUser()).thenReturn(mCurrentUser);
91
Robert Snoeberger71e50792019-02-15 15:48:01 -050092 mClockManager = new ClockManager(getContext(), mMockInjectionInflationController,
Robert Snoeberger3f4650c2019-03-25 14:41:42 -040093 mMockPluginManager, mMockColorExtractor, mMockContentResolver,
Lucas Dupind93e95f2019-05-01 00:49:35 +000094 mMockCurrentUserObserable, mMockSettingsWrapper, mFakeDockManager);
Robert Snoeberger71e50792019-02-15 15:48:01 -050095
Robert Snoebergerd8445ea2019-03-27 10:41:23 -040096 mClockManager.addOnClockChangedListener(mMockListener1);
97 mClockManager.addOnClockChangedListener(mMockListener2);
98 reset(mMockListener1, mMockListener2);
99
Robert Snoeberger71e50792019-02-15 15:48:01 -0500100 mContentObserver = mClockManager.getContentObserver();
Robert Snoebergerb300a4e2019-02-13 20:13:53 +0000101 }
102
103 @After
104 public void tearDown() {
Robert Snoebergerd8445ea2019-03-27 10:41:23 -0400105 mClockManager.removeOnClockChangedListener(mMockListener1);
106 mClockManager.removeOnClockChangedListener(mMockListener2);
Robert Snoebergerb300a4e2019-02-13 20:13:53 +0000107 }
108
109 @Test
110 public void dockEvent() {
111 mFakeDockManager.setDockEvent(DockManager.STATE_DOCKED);
112 assertThat(mClockManager.isDocked()).isTrue();
113 }
114
115 @Test
116 public void undockEvent() {
117 mFakeDockManager.setDockEvent(DockManager.STATE_NONE);
118 assertThat(mClockManager.isDocked()).isFalse();
119 }
Robert Snoeberger71e50792019-02-15 15:48:01 -0500120
121 @Test
122 public void getCurrentClock_default() {
123 // GIVEN that settings doesn't contain any values
Robert Snoeberger372e13f2019-04-08 17:07:14 -0400124 when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(null);
125 when(mMockSettingsWrapper.getDockedClockFace(anyInt())).thenReturn(null);
Robert Snoeberger71e50792019-02-15 15:48:01 -0500126 // WHEN settings change event is fired
Robert Snoebergerbe2a1882019-04-10 13:48:02 -0400127 mContentObserver.onChange(false, SETTINGS_URI, MAIN_USER_ID);
Robert Snoeberger71e50792019-02-15 15:48:01 -0500128 // THEN the result is null, indicated the default clock face should be used.
129 assertThat(mClockManager.getCurrentClock()).isNull();
130 }
131
132 @Test
133 public void getCurrentClock_customClock() {
134 // GIVEN that settings is set to the bubble clock face
Robert Snoeberger372e13f2019-04-08 17:07:14 -0400135 when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(BUBBLE_CLOCK);
Robert Snoeberger71e50792019-02-15 15:48:01 -0500136 // WHEN settings change event is fired
Robert Snoebergerbe2a1882019-04-10 13:48:02 -0400137 mContentObserver.onChange(false, SETTINGS_URI, MAIN_USER_ID);
Robert Snoeberger71e50792019-02-15 15:48:01 -0500138 // THEN the plugin is the bubble clock face.
139 assertThat(mClockManager.getCurrentClock()).isInstanceOf(BUBBLE_CLOCK_CLASS);
140 }
141
142 @Test
Robert Snoebergerd8445ea2019-03-27 10:41:23 -0400143 public void onClockChanged_customClock() {
144 // GIVEN that settings is set to the bubble clock face
Robert Snoeberger372e13f2019-04-08 17:07:14 -0400145 when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(BUBBLE_CLOCK);
Robert Snoebergerd8445ea2019-03-27 10:41:23 -0400146 // WHEN settings change event is fired
Robert Snoebergerbe2a1882019-04-10 13:48:02 -0400147 mContentObserver.onChange(false, SETTINGS_URI, MAIN_USER_ID);
Robert Snoebergerd8445ea2019-03-27 10:41:23 -0400148 // THEN the plugin is the bubble clock face.
149 ArgumentCaptor<ClockPlugin> captor = ArgumentCaptor.forClass(ClockPlugin.class);
150 verify(mMockListener1).onClockChanged(captor.capture());
151 assertThat(captor.getValue()).isInstanceOf(BUBBLE_CLOCK_CLASS);
152 }
153
154 @Test
155 public void onClockChanged_uniqueInstances() {
156 // GIVEN that settings is set to the bubble clock face
Robert Snoeberger372e13f2019-04-08 17:07:14 -0400157 when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(BUBBLE_CLOCK);
Robert Snoebergerd8445ea2019-03-27 10:41:23 -0400158 // WHEN settings change event is fired
Robert Snoebergerbe2a1882019-04-10 13:48:02 -0400159 mContentObserver.onChange(false, SETTINGS_URI, MAIN_USER_ID);
Robert Snoebergerd8445ea2019-03-27 10:41:23 -0400160 // THEN the listeners receive separate instances of the Bubble clock plugin.
161 ArgumentCaptor<ClockPlugin> captor1 = ArgumentCaptor.forClass(ClockPlugin.class);
162 ArgumentCaptor<ClockPlugin> captor2 = ArgumentCaptor.forClass(ClockPlugin.class);
163 verify(mMockListener1).onClockChanged(captor1.capture());
164 verify(mMockListener2).onClockChanged(captor2.capture());
165 assertThat(captor1.getValue()).isInstanceOf(BUBBLE_CLOCK_CLASS);
166 assertThat(captor2.getValue()).isInstanceOf(BUBBLE_CLOCK_CLASS);
167 assertThat(captor1.getValue()).isNotSameAs(captor2.getValue());
168 }
169
170 @Test
Robert Snoeberger71e50792019-02-15 15:48:01 -0500171 public void getCurrentClock_badSettingsValue() {
172 // GIVEN that settings contains a value that doesn't correspond to a
173 // custom clock face.
Robert Snoeberger372e13f2019-04-08 17:07:14 -0400174 when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn("bad value");
Robert Snoeberger71e50792019-02-15 15:48:01 -0500175 // WHEN settings change event is fired
Robert Snoebergerbe2a1882019-04-10 13:48:02 -0400176 mContentObserver.onChange(false, SETTINGS_URI, MAIN_USER_ID);
Robert Snoeberger71e50792019-02-15 15:48:01 -0500177 // THEN the result is null.
178 assertThat(mClockManager.getCurrentClock()).isNull();
179 }
180
181 @Test
182 public void getCurrentClock_dockedDefault() {
183 // WHEN dock event is fired
184 mFakeDockManager.setDockEvent(DockManager.STATE_DOCKED);
185 // THEN the result is null, indicating the default clock face.
186 assertThat(mClockManager.getCurrentClock()).isNull();
187 }
188
189 @Test
190 public void getCurrentClock_dockedCustomClock() {
191 // GIVEN settings is set to the bubble clock face
Robert Snoeberger372e13f2019-04-08 17:07:14 -0400192 when(mMockSettingsWrapper.getDockedClockFace(anyInt())).thenReturn(BUBBLE_CLOCK);
Robert Snoeberger71e50792019-02-15 15:48:01 -0500193 // WHEN dock event fires
194 mFakeDockManager.setDockEvent(DockManager.STATE_DOCKED);
195 // THEN the plugin is the bubble clock face.
196 assertThat(mClockManager.getCurrentClock()).isInstanceOf(BUBBLE_CLOCK_CLASS);
197 }
198
199 @Test
200 public void getCurrentClock_badDockedSettingsValue() {
201 // GIVEN settings contains a value that doesn't correspond to an available clock face.
Robert Snoeberger372e13f2019-04-08 17:07:14 -0400202 when(mMockSettingsWrapper.getDockedClockFace(anyInt())).thenReturn("bad value");
Robert Snoeberger71e50792019-02-15 15:48:01 -0500203 // WHEN dock event fires
204 mFakeDockManager.setDockEvent(DockManager.STATE_DOCKED);
205 // THEN the result is null.
206 assertThat(mClockManager.getCurrentClock()).isNull();
207 }
208
209 @Test
210 public void getCurrentClock_badDockedSettingsFallback() {
211 // GIVEN settings contains a value that doesn't correspond to an available clock face, but
212 // locked screen settings is set to bubble clock.
Robert Snoeberger372e13f2019-04-08 17:07:14 -0400213 when(mMockSettingsWrapper.getDockedClockFace(anyInt())).thenReturn("bad value");
214 when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(BUBBLE_CLOCK);
Robert Snoeberger71e50792019-02-15 15:48:01 -0500215 // WHEN dock event is fired
216 mFakeDockManager.setDockEvent(DockManager.STATE_DOCKED);
217 // THEN the plugin is the bubble clock face.
218 assertThat(mClockManager.getCurrentClock()).isInstanceOf(BUBBLE_CLOCK_CLASS);
219 }
Robert Snoebergerbe2a1882019-04-10 13:48:02 -0400220
221 @Test
222 public void onUserChanged_defaultClock() {
223 // WHEN the user changes
224 mCurrentUser.setValue(SECONDARY_USER_ID);
225 // THEN the plugin is null for the default clock face
226 assertThat(mClockManager.getCurrentClock()).isNull();
227 }
228
229 @Test
230 public void onUserChanged_customClock() {
231 // GIVEN that a second user has selected the bubble clock face
232 when(mMockSettingsWrapper.getLockScreenCustomClockFace(SECONDARY_USER_ID)).thenReturn(
233 BUBBLE_CLOCK);
234 // WHEN the user changes
235 mCurrentUser.setValue(SECONDARY_USER_ID);
236 // THEN the plugin is the bubble clock face.
237 assertThat(mClockManager.getCurrentClock()).isInstanceOf(BUBBLE_CLOCK_CLASS);
238 }
239
240 @Test
241 public void onUserChanged_docked() {
242 // GIVEN device is docked
243 mFakeDockManager.setDockEvent(DockManager.STATE_DOCKED);
244 // AND the second user as selected the bubble clock for the dock
245 when(mMockSettingsWrapper.getDockedClockFace(SECONDARY_USER_ID)).thenReturn(BUBBLE_CLOCK);
246 // WHEN the user changes
247 mCurrentUser.setValue(SECONDARY_USER_ID);
248 // THEN the plugin is the bubble clock face.
249 assertThat(mClockManager.getCurrentClock()).isInstanceOf(BUBBLE_CLOCK_CLASS);
250 }
Robert Snoebergerb300a4e2019-02-13 20:13:53 +0000251}