• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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.systemui.statusbar.phone;
18 
19 import static com.android.systemui.Flags.FLAG_QS_NEW_PIPELINE;
20 import static com.android.systemui.qs.dagger.QSFlagsModule.RBC_AVAILABLE;
21 import static com.android.systemui.statusbar.phone.AutoTileManager.DEVICE_CONTROLS;
22 
23 import static org.junit.Assert.assertEquals;
24 import static org.junit.Assert.assertFalse;
25 import static org.junit.Assert.assertNull;
26 import static org.junit.Assert.assertTrue;
27 import static org.junit.Assert.fail;
28 import static org.mockito.ArgumentMatchers.any;
29 import static org.mockito.ArgumentMatchers.eq;
30 import static org.mockito.ArgumentMatchers.isNotNull;
31 import static org.mockito.ArgumentMatchers.isNull;
32 import static org.mockito.Mockito.doReturn;
33 import static org.mockito.Mockito.inOrder;
34 import static org.mockito.Mockito.mock;
35 import static org.mockito.Mockito.never;
36 import static org.mockito.Mockito.times;
37 import static org.mockito.Mockito.verify;
38 import static org.mockito.Mockito.verifyNoMoreInteractions;
39 import static org.mockito.Mockito.when;
40 
41 import android.content.ComponentName;
42 import android.content.Context;
43 import android.content.pm.PackageManager;
44 import android.hardware.display.ColorDisplayManager;
45 import android.hardware.display.NightDisplayListener;
46 import android.os.Handler;
47 import android.os.UserHandle;
48 import android.testing.TestableLooper;
49 import android.testing.TestableLooper.RunWithLooper;
50 
51 import androidx.test.ext.junit.runners.AndroidJUnit4;
52 import androidx.test.filters.SmallTest;
53 
54 import com.android.systemui.SysuiTestCase;
55 import com.android.systemui.dagger.NightDisplayListenerModule;
56 import com.android.systemui.plugins.qs.QSTile;
57 import com.android.systemui.qs.AutoAddTracker;
58 import com.android.systemui.qs.QSHost;
59 import com.android.systemui.qs.ReduceBrightColorsController;
60 import com.android.systemui.qs.UserSettingObserver;
61 import com.android.systemui.qs.external.CustomTile;
62 import com.android.systemui.res.R;
63 import com.android.systemui.statusbar.policy.CastController;
64 import com.android.systemui.statusbar.policy.CastController.CastDevice;
65 import com.android.systemui.statusbar.policy.DataSaverController;
66 import com.android.systemui.statusbar.policy.DeviceControlsController;
67 import com.android.systemui.statusbar.policy.HotspotController;
68 import com.android.systemui.statusbar.policy.SafetyController;
69 import com.android.systemui.statusbar.policy.WalletController;
70 import com.android.systemui.util.settings.FakeSettings;
71 import com.android.systemui.util.settings.SecureSettings;
72 
73 import org.junit.After;
74 import org.junit.Before;
75 import org.junit.Test;
76 import org.junit.runner.RunWith;
77 import org.mockito.Answers;
78 import org.mockito.ArgumentCaptor;
79 import org.mockito.InOrder;
80 import org.mockito.Mock;
81 import org.mockito.Mockito;
82 import org.mockito.MockitoAnnotations;
83 import org.mockito.Spy;
84 import org.mockito.stubbing.Answer;
85 
86 import java.util.ArrayList;
87 import java.util.Collections;
88 import java.util.List;
89 
90 import javax.inject.Named;
91 
92 @RunWith(AndroidJUnit4.class)
93 @RunWithLooper
94 @SmallTest
95 public class AutoTileManagerTest extends SysuiTestCase {
96 
97     private static final String TEST_SETTING = "setting";
98     private static final String TEST_SPEC = "spec";
99     private static final String TEST_SETTING_COMPONENT = "setting_component";
100     private static final String TEST_COMPONENT = "test_pkg/test_cls";
101     private static final String TEST_CUSTOM_SPEC = "custom(" + TEST_COMPONENT + ")";
102     private static final String TEST_CUSTOM_SAFETY_CLASS = "safety_cls";
103     private static final String TEST_CUSTOM_SAFETY_PKG = "safety_pkg";
104     private static final String TEST_CUSTOM_SAFETY_SPEC = CustomTile.toSpec(new ComponentName(
105             TEST_CUSTOM_SAFETY_PKG, TEST_CUSTOM_SAFETY_CLASS));
106     private static final String SEPARATOR = AutoTileManager.SETTING_SEPARATOR;
107 
108     private static final int USER = 0;
109 
110     @Mock private QSHost mQsHost;
111     @Mock private AutoAddTracker mAutoAddTracker;
112     @Mock private CastController mCastController;
113     @Mock private HotspotController mHotspotController;
114     @Mock private DataSaverController mDataSaverController;
115     @Mock private ManagedProfileController mManagedProfileController;
116     @Mock private NightDisplayListener mNightDisplayListener;
117     @Mock(answer = Answers.RETURNS_SELF)
118     private NightDisplayListenerModule.Builder mNightDisplayListenerBuilder;
119     @Mock private ReduceBrightColorsController mReduceBrightColorsController;
120     @Mock private DeviceControlsController mDeviceControlsController;
121     @Mock private WalletController mWalletController;
122     @Mock private SafetyController mSafetyController;
123     @Mock(answer = Answers.RETURNS_SELF)
124     private AutoAddTracker.Builder mAutoAddTrackerBuilder;
125     @Mock private Context mUserContext;
126     @Spy private PackageManager mPackageManager;
127     private final boolean mIsReduceBrightColorsAvailable = true;
128 
129     private AutoTileManager mAutoTileManager; // under test
130 
131     private SecureSettings mSecureSettings;
132     private ManagedProfileController.Callback mManagedProfileCallback;
133 
134     @Before
setUp()135     public void setUp() throws Exception {
136         MockitoAnnotations.initMocks(this);
137         mSecureSettings = new FakeSettings();
138 
139         mSetFlagsRule.disableFlags(FLAG_QS_NEW_PIPELINE);
140 
141         mContext.getOrCreateTestableResources().addOverride(
142                 R.array.config_quickSettingsAutoAdd,
143                 new String[] {
144                         TEST_SETTING + SEPARATOR + TEST_SPEC,
145                         TEST_SETTING_COMPONENT + SEPARATOR + TEST_CUSTOM_SPEC
146                 }
147         );
148         mContext.getOrCreateTestableResources().addOverride(
149                 com.android.internal.R.bool.config_nightDisplayAvailable, true);
150         mContext.getOrCreateTestableResources().addOverride(
151                 R.string.safety_quick_settings_tile_class, TEST_CUSTOM_SAFETY_CLASS);
152 
153         when(mAutoAddTrackerBuilder.build()).thenReturn(mAutoAddTracker);
154         when(mQsHost.getUserContext()).thenReturn(mUserContext);
155         when(mUserContext.getUser()).thenReturn(UserHandle.of(USER));
156         mPackageManager = Mockito.spy(mContext.getPackageManager());
157         when(mPackageManager.getPermissionControllerPackageName())
158                 .thenReturn(TEST_CUSTOM_SAFETY_PKG);
159         Context context = Mockito.spy(mContext);
160         when(context.getPackageManager()).thenReturn(mPackageManager);
161         when(mNightDisplayListenerBuilder.build()).thenReturn(mNightDisplayListener);
162 
163         mAutoTileManager = createAutoTileManager(context);
164         mAutoTileManager.init();
165     }
166 
167     @After
tearDown()168     public void tearDown() {
169         mAutoTileManager.destroy();
170     }
171 
createAutoTileManager( Context context, AutoAddTracker.Builder autoAddTrackerBuilder, HotspotController hotspotController, DataSaverController dataSaverController, ManagedProfileController managedProfileController, NightDisplayListenerModule.Builder nightDisplayListenerBuilder, CastController castController, ReduceBrightColorsController reduceBrightColorsController, DeviceControlsController deviceControlsController, WalletController walletController, SafetyController safetyController, @Named(RBC_AVAILABLE) boolean isReduceBrightColorsAvailable)172     private AutoTileManager createAutoTileManager(
173             Context context,
174             AutoAddTracker.Builder autoAddTrackerBuilder,
175             HotspotController hotspotController,
176             DataSaverController dataSaverController,
177             ManagedProfileController managedProfileController,
178             NightDisplayListenerModule.Builder nightDisplayListenerBuilder,
179             CastController castController,
180             ReduceBrightColorsController reduceBrightColorsController,
181             DeviceControlsController deviceControlsController,
182             WalletController walletController,
183             SafetyController safetyController,
184             @Named(RBC_AVAILABLE) boolean isReduceBrightColorsAvailable) {
185         return new AutoTileManager(context, autoAddTrackerBuilder, mQsHost,
186                 Handler.createAsync(TestableLooper.get(this).getLooper()),
187                 mSecureSettings,
188                 hotspotController,
189                 dataSaverController,
190                 managedProfileController,
191                 mNightDisplayListenerBuilder,
192                 castController,
193                 reduceBrightColorsController,
194                 deviceControlsController,
195                 walletController,
196                 safetyController,
197                 isReduceBrightColorsAvailable);
198     }
199 
createAutoTileManager(Context context)200     private AutoTileManager createAutoTileManager(Context context) {
201         return createAutoTileManager(context, mAutoAddTrackerBuilder, mHotspotController,
202                 mDataSaverController, mManagedProfileController, mNightDisplayListenerBuilder,
203                 mCastController, mReduceBrightColorsController, mDeviceControlsController,
204                 mWalletController, mSafetyController, mIsReduceBrightColorsAvailable);
205     }
206 
207     @Test
testCreatedAutoTileManagerIsNotInitialized()208     public void testCreatedAutoTileManagerIsNotInitialized() {
209         AutoAddTracker.Builder builder = mock(AutoAddTracker.Builder.class, Answers.RETURNS_SELF);
210         AutoAddTracker tracker = mock(AutoAddTracker.class);
211         when(builder.build()).thenReturn(tracker);
212         HotspotController hC = mock(HotspotController.class);
213         DataSaverController dSC = mock(DataSaverController.class);
214         ManagedProfileController mPC = mock(ManagedProfileController.class);
215         NightDisplayListenerModule.Builder nDSB = mock(NightDisplayListenerModule.Builder.class);
216         CastController cC = mock(CastController.class);
217         ReduceBrightColorsController rBC = mock(ReduceBrightColorsController.class);
218         DeviceControlsController dCC = mock(DeviceControlsController.class);
219         WalletController wC = mock(WalletController.class);
220         SafetyController sC = mock(SafetyController.class);
221 
222         AutoTileManager manager =
223                 createAutoTileManager(mock(Context.class), builder, hC, dSC, mPC, nDSB, cC, rBC,
224                         dCC, wC, sC, true);
225 
226         verify(tracker, never()).initialize();
227         verify(hC, never()).addCallback(any());
228         verify(dSC, never()).addCallback(any());
229         verify(mPC, never()).addCallback(any());
230         verifyNoMoreInteractions(nDSB);
231         verify(cC, never()).addCallback(any());
232         verify(rBC, never()).addCallback(any());
233         verify(dCC, never()).setCallback(any());
234         verify(wC, never()).getWalletPosition();
235         verify(sC, never()).addCallback(any());
236         assertNull(manager.getSecureSettingForKey(TEST_SETTING));
237         assertNull(manager.getSecureSettingForKey(TEST_SETTING_COMPONENT));
238     }
239 
240     @Test
testChangeUserWhenNotInitializedThrows()241     public void testChangeUserWhenNotInitializedThrows() {
242         AutoTileManager manager = createAutoTileManager(mock(Context.class));
243 
244         try {
245             manager.changeUser(UserHandle.of(USER + 1));
246             fail();
247         } catch (Exception e) {
248             // This should throw and take this path
249         }
250     }
251 
252     @Test
testChangeUserCallbacksStoppedAndStarted()253     public void testChangeUserCallbacksStoppedAndStarted() throws Exception {
254         TestableLooper.get(this).runWithLooper(() ->
255                 mAutoTileManager.changeUser(UserHandle.of(USER + 1))
256         );
257 
258         InOrder inOrderHotspot = inOrder(mHotspotController);
259         inOrderHotspot.verify(mHotspotController).removeCallback(any());
260         inOrderHotspot.verify(mHotspotController).addCallback(any());
261 
262         InOrder inOrderDataSaver = inOrder(mDataSaverController);
263         inOrderDataSaver.verify(mDataSaverController).removeCallback(any());
264         inOrderDataSaver.verify(mDataSaverController).addCallback(any());
265 
266         InOrder inOrderManagedProfile = inOrder(mManagedProfileController);
267         inOrderManagedProfile.verify(mManagedProfileController).removeCallback(any());
268         inOrderManagedProfile.verify(mManagedProfileController).addCallback(any());
269 
270         if (ColorDisplayManager.isNightDisplayAvailable(mContext)) {
271             InOrder inOrderNightDisplay = inOrder(mNightDisplayListener);
272             inOrderNightDisplay.verify(mNightDisplayListener).setCallback(isNull());
273             inOrderNightDisplay.verify(mNightDisplayListener).setCallback(isNotNull());
274         }
275 
276         InOrder inOrderReduceBrightColors = inOrder(mReduceBrightColorsController);
277         inOrderReduceBrightColors.verify(mReduceBrightColorsController).removeCallback(any());
278         inOrderReduceBrightColors.verify(mReduceBrightColorsController).addCallback(any());
279 
280         InOrder inOrderCast = inOrder(mCastController);
281         inOrderCast.verify(mCastController).removeCallback(any());
282         inOrderCast.verify(mCastController).addCallback(any());
283 
284         InOrder inOrderDevices = inOrder(mDeviceControlsController);
285         inOrderDevices.verify(mDeviceControlsController).removeCallback();
286         inOrderDevices.verify(mDeviceControlsController).setCallback(any());
287 
288         verify(mWalletController, times(2)).getWalletPosition();
289 
290         InOrder inOrderSafety = inOrder(mSafetyController);
291         inOrderSafety.verify(mSafetyController).removeCallback(any());
292         inOrderSafety.verify(mSafetyController).addCallback(any());
293 
294         UserSettingObserver setting = mAutoTileManager.getSecureSettingForKey(TEST_SETTING);
295         assertEquals(USER + 1, setting.getCurrentUser());
296         assertTrue(setting.isListening());
297     }
298 
299     @Test
testChangeUserSomeCallbacksNotAdded()300     public void testChangeUserSomeCallbacksNotAdded() throws Exception {
301         when(mAutoAddTracker.isAdded("hotspot")).thenReturn(true);
302         when(mAutoAddTracker.isAdded("work")).thenReturn(true);
303         when(mAutoAddTracker.isAdded("cast")).thenReturn(true);
304         when(mAutoAddTracker.isAdded(TEST_SPEC)).thenReturn(true);
305 
306         TestableLooper.get(this).runWithLooper(() ->
307                 mAutoTileManager.changeUser(UserHandle.of(USER + 1))
308         );
309 
310         verify(mAutoAddTracker).changeUser(UserHandle.of(USER + 1));
311 
312         InOrder inOrderHotspot = inOrder(mHotspotController);
313         inOrderHotspot.verify(mHotspotController).removeCallback(any());
314         inOrderHotspot.verify(mHotspotController, never()).addCallback(any());
315 
316         InOrder inOrderDataSaver = inOrder(mDataSaverController);
317         inOrderDataSaver.verify(mDataSaverController).removeCallback(any());
318         inOrderDataSaver.verify(mDataSaverController).addCallback(any());
319 
320         InOrder inOrderManagedProfile = inOrder(mManagedProfileController);
321         inOrderManagedProfile.verify(mManagedProfileController).removeCallback(any());
322         inOrderManagedProfile.verify(mManagedProfileController).addCallback(any());
323 
324         if (ColorDisplayManager.isNightDisplayAvailable(mContext)) {
325             InOrder inOrderNightDisplay = inOrder(mNightDisplayListener);
326             inOrderNightDisplay.verify(mNightDisplayListener).setCallback(isNull());
327             inOrderNightDisplay.verify(mNightDisplayListener).setCallback(isNotNull());
328         }
329 
330         InOrder inOrderReduceBrightColors = inOrder(mReduceBrightColorsController);
331         inOrderReduceBrightColors.verify(mReduceBrightColorsController).removeCallback(any());
332         inOrderReduceBrightColors.verify(mReduceBrightColorsController).addCallback(any());
333 
334         InOrder inOrderCast = inOrder(mCastController);
335         inOrderCast.verify(mCastController).removeCallback(any());
336         inOrderCast.verify(mCastController, never()).addCallback(any());
337 
338         InOrder inOrderDevices = inOrder(mDeviceControlsController);
339         inOrderDevices.verify(mDeviceControlsController).removeCallback();
340         inOrderDevices.verify(mDeviceControlsController).setCallback(any());
341 
342         verify(mWalletController, times(2)).getWalletPosition();
343 
344         InOrder inOrderSafety = inOrder(mSafetyController);
345         inOrderSafety.verify(mSafetyController).removeCallback(any());
346         inOrderSafety.verify(mSafetyController).addCallback(any());
347 
348         UserSettingObserver setting = mAutoTileManager.getSecureSettingForKey(TEST_SETTING);
349         assertEquals(USER + 1, setting.getCurrentUser());
350         assertFalse(setting.isListening());
351     }
352 
353     @Test
testGetCurrentUserId()354     public void testGetCurrentUserId() throws Exception {
355         assertEquals(USER, mAutoTileManager.getCurrentUserId());
356 
357         TestableLooper.get(this).runWithLooper(() ->
358                 mAutoTileManager.changeUser(UserHandle.of(USER + 100))
359         );
360 
361         assertEquals(USER + 100, mAutoTileManager.getCurrentUserId());
362     }
363 
364     @Test
nightTileAdded_whenActivated()365     public void nightTileAdded_whenActivated() {
366         if (!ColorDisplayManager.isNightDisplayAvailable(mContext)) {
367             return;
368         }
369         mAutoTileManager.mNightDisplayCallback.onActivated(true);
370         verify(mQsHost).addTile("night");
371     }
372 
373     @Test
nightTileNotAdded_whenDeactivated()374     public void nightTileNotAdded_whenDeactivated() {
375         if (!ColorDisplayManager.isNightDisplayAvailable(mContext)) {
376             return;
377         }
378         mAutoTileManager.mNightDisplayCallback.onActivated(false);
379         verify(mQsHost, never()).addTile("night");
380     }
381 
382     @Test
nightTileAdded_whenNightModeTwilight()383     public void nightTileAdded_whenNightModeTwilight() {
384         if (!ColorDisplayManager.isNightDisplayAvailable(mContext)) {
385             return;
386         }
387         mAutoTileManager.mNightDisplayCallback.onAutoModeChanged(
388                 ColorDisplayManager.AUTO_MODE_TWILIGHT);
389         verify(mQsHost).addTile("night");
390     }
391 
392     @Test
nightTileAdded_whenNightModeCustom()393     public void nightTileAdded_whenNightModeCustom() {
394         if (!ColorDisplayManager.isNightDisplayAvailable(mContext)) {
395             return;
396         }
397         mAutoTileManager.mNightDisplayCallback.onAutoModeChanged(
398                 ColorDisplayManager.AUTO_MODE_CUSTOM_TIME);
399         verify(mQsHost).addTile("night");
400     }
401 
402     @Test
nightTileNotAdded_whenNightModeDisabled()403     public void nightTileNotAdded_whenNightModeDisabled() {
404         if (!ColorDisplayManager.isNightDisplayAvailable(mContext)) {
405             return;
406         }
407         mAutoTileManager.mNightDisplayCallback.onAutoModeChanged(
408                 ColorDisplayManager.AUTO_MODE_DISABLED);
409         verify(mQsHost, never()).addTile("night");
410     }
411 
412     @Test
reduceBrightColorsTileAdded_whenActivated()413     public void reduceBrightColorsTileAdded_whenActivated() {
414         mAutoTileManager.mReduceBrightColorsCallback.onActivated(true);
415         verify(mQsHost).addTile("reduce_brightness");
416     }
417 
418     @Test
reduceBrightColorsTileNotAdded_whenDeactivated()419     public void reduceBrightColorsTileNotAdded_whenDeactivated() {
420         mAutoTileManager.mReduceBrightColorsCallback.onActivated(false);
421         verify(mQsHost, never()).addTile("reduce_brightness");
422     }
423 
buildFakeCastDevice(boolean isCasting)424     private static List<CastDevice> buildFakeCastDevice(boolean isCasting) {
425         CastDevice cd = new CastDevice();
426         cd.state = isCasting ? CastDevice.STATE_CONNECTED : CastDevice.STATE_DISCONNECTED;
427         return Collections.singletonList(cd);
428     }
429 
430     @Test
castTileAdded_whenDeviceIsCasting()431     public void castTileAdded_whenDeviceIsCasting() {
432         doReturn(buildFakeCastDevice(true)).when(mCastController).getCastDevices();
433         mAutoTileManager.mCastCallback.onCastDevicesChanged();
434         verify(mQsHost).addTile("cast");
435     }
436 
437     @Test
castTileNotAdded_whenDeviceIsNotCasting()438     public void castTileNotAdded_whenDeviceIsNotCasting() {
439         doReturn(buildFakeCastDevice(false)).when(mCastController).getCastDevices();
440         mAutoTileManager.mCastCallback.onCastDevicesChanged();
441         verify(mQsHost, never()).addTile("cast");
442     }
443 
444     @Test
testSettingTileAdded_onChanged()445     public void testSettingTileAdded_onChanged() {
446         changeValue(TEST_SETTING, 1);
447         verify(mAutoAddTracker).setTileAdded(TEST_SPEC);
448         verify(mQsHost).addTile(TEST_SPEC);
449     }
450 
451     @Test
testSettingTileAddedComponentAtEnd_onChanged()452     public void testSettingTileAddedComponentAtEnd_onChanged() {
453         changeValue(TEST_SETTING_COMPONENT, 1);
454         verify(mAutoAddTracker).setTileAdded(TEST_CUSTOM_SPEC);
455         verify(mQsHost).addTile(ComponentName.unflattenFromString(TEST_COMPONENT)
456             , /* end */ true);
457     }
458 
459     @Test
testSettingTileAdded_onlyOnce()460     public void testSettingTileAdded_onlyOnce() {
461         changeValue(TEST_SETTING, 1);
462         changeValue(TEST_SETTING, 2);
463         verify(mAutoAddTracker).setTileAdded(TEST_SPEC);
464         verify(mQsHost).addTile(TEST_SPEC);
465     }
466 
467     @Test
testSettingTileNotAdded_onChangedTo0()468     public void testSettingTileNotAdded_onChangedTo0() {
469         changeValue(TEST_SETTING, 0);
470         verify(mAutoAddTracker, never()).setTileAdded(TEST_SPEC);
471         verify(mQsHost, never()).addTile(TEST_SPEC);
472     }
473 
474     @Test
testSettingTileNotAdded_ifPreviouslyAdded()475     public void testSettingTileNotAdded_ifPreviouslyAdded() {
476         when(mAutoAddTracker.isAdded(TEST_SPEC)).thenReturn(true);
477 
478         changeValue(TEST_SETTING, 1);
479         verify(mAutoAddTracker, never()).setTileAdded(TEST_SPEC);
480         verify(mQsHost, never()).addTile(TEST_SPEC);
481     }
482 
483     @Test
testSafetyTileNotAdded_ifPreviouslyAdded()484     public void testSafetyTileNotAdded_ifPreviouslyAdded() {
485         ComponentName safetyComponent = CustomTile.getComponentFromSpec(TEST_CUSTOM_SAFETY_SPEC);
486         mAutoTileManager.init();
487         verify(mQsHost, times(1)).addTile(safetyComponent, true);
488         when(mAutoAddTracker.isAdded(TEST_CUSTOM_SAFETY_SPEC)).thenReturn(true);
489         mAutoTileManager.init();
490         verify(mQsHost, times(1)).addTile(safetyComponent, true);
491     }
492 
493     @Test
testSafetyTileAdded_onUserChange()494     public void testSafetyTileAdded_onUserChange() {
495         ComponentName safetyComponent = CustomTile.getComponentFromSpec(TEST_CUSTOM_SAFETY_SPEC);
496         mAutoTileManager.init();
497         verify(mQsHost, times(1)).addTile(safetyComponent, true);
498         when(mAutoAddTracker.isAdded(TEST_CUSTOM_SAFETY_SPEC)).thenReturn(false);
499         mAutoTileManager.changeUser(UserHandle.of(USER + 1));
500         verify(mQsHost, times(2)).addTile(safetyComponent, true);
501     }
502 
503     @Test
testSafetyTileRemoved_onSafetyCenterDisable()504     public void testSafetyTileRemoved_onSafetyCenterDisable() {
505         ComponentName safetyComponent = CustomTile.getComponentFromSpec(TEST_CUSTOM_SAFETY_SPEC);
506         mAutoTileManager.init();
507         when(mAutoAddTracker.isAdded(TEST_CUSTOM_SAFETY_SPEC)).thenReturn(true);
508         mAutoTileManager.mSafetyCallback.onSafetyCenterEnableChanged(false);
509         verify(mQsHost, times(1)).removeTile(TEST_CUSTOM_SAFETY_SPEC);
510     }
511 
512     @Test
testSafetyTileAdded_onSafetyCenterEnable()513     public void testSafetyTileAdded_onSafetyCenterEnable() {
514         ComponentName safetyComponent = CustomTile.getComponentFromSpec(TEST_CUSTOM_SAFETY_SPEC);
515         mAutoTileManager.init();
516         verify(mQsHost, times(1)).addTile(safetyComponent, true);
517         mAutoTileManager.mSafetyCallback.onSafetyCenterEnableChanged(false);
518         mAutoTileManager.mSafetyCallback.onSafetyCenterEnableChanged(true);
519         verify(mQsHost, times(2)).addTile(safetyComponent, true);
520     }
521 
522     @Test
managedProfileAdded_tileAdded()523     public void managedProfileAdded_tileAdded() {
524         when(mAutoAddTracker.isAdded(eq("work"))).thenReturn(false);
525         when(mAutoAddTracker.getRestoredTilePosition(eq("work"))).thenReturn(2);
526         mAutoTileManager = createAutoTileManager(mContext);
527         Mockito.doAnswer((Answer<Object>) invocation -> {
528             mManagedProfileCallback = invocation.getArgument(0);
529             return null;
530         }).when(mManagedProfileController).addCallback(any());
531         mAutoTileManager.init();
532         when(mManagedProfileController.hasActiveProfile()).thenReturn(true);
533 
534         mManagedProfileCallback.onManagedProfileChanged();
535 
536         verify(mQsHost, times(1)).addTile(eq("work"), eq(2));
537         verify(mAutoAddTracker, times(1)).setTileAdded(eq("work"));
538     }
539 
540     @Test
managedProfileRemoved_tileRemoved()541     public void managedProfileRemoved_tileRemoved() {
542         when(mAutoAddTracker.isAdded(eq("work"))).thenReturn(true);
543         mAutoTileManager = createAutoTileManager(mContext);
544         Mockito.doAnswer((Answer<Object>) invocation -> {
545             mManagedProfileCallback = invocation.getArgument(0);
546             return null;
547         }).when(mManagedProfileController).addCallback(any());
548         mAutoTileManager.init();
549         when(mManagedProfileController.hasActiveProfile()).thenReturn(false);
550 
551         mManagedProfileCallback.onManagedProfileChanged();
552 
553         verify(mQsHost, times(1)).removeTile(eq("work"));
554         verify(mAutoAddTracker, times(1)).setTileRemoved(eq("work"));
555     }
556 
557     @Test
testAddControlsTileIfNotPresent()558     public void testAddControlsTileIfNotPresent() {
559         String spec = DEVICE_CONTROLS;
560         when(mAutoAddTracker.isAdded(eq(spec))).thenReturn(false);
561         when(mQsHost.getTiles()).thenReturn(new ArrayList<>());
562 
563         mAutoTileManager.init();
564         ArgumentCaptor<DeviceControlsController.Callback> captor =
565                 ArgumentCaptor.forClass(DeviceControlsController.Callback.class);
566 
567         verify(mDeviceControlsController).setCallback(captor.capture());
568 
569         captor.getValue().onControlsUpdate(3);
570         verify(mQsHost).addTile(spec, 3);
571         verify(mAutoAddTracker).setTileAdded(spec);
572     }
573 
574     @Test
testDontAddControlsTileIfPresent()575     public void testDontAddControlsTileIfPresent() {
576         String spec = DEVICE_CONTROLS;
577         when(mAutoAddTracker.isAdded(eq(spec))).thenReturn(false);
578         when(mQsHost.getTiles()).thenReturn(new ArrayList<>());
579 
580         mAutoTileManager.init();
581         ArgumentCaptor<DeviceControlsController.Callback> captor =
582                 ArgumentCaptor.forClass(DeviceControlsController.Callback.class);
583 
584         verify(mDeviceControlsController).setCallback(captor.capture());
585 
586         captor.getValue().removeControlsAutoTracker();
587         verify(mQsHost, never()).addTile(spec, 3);
588         verify(mAutoAddTracker, never()).setTileAdded(spec);
589         verify(mAutoAddTracker).setTileRemoved(spec);
590     }
591 
592     @Test
testRemoveControlsTileFromTrackerWhenRequested()593     public void testRemoveControlsTileFromTrackerWhenRequested() {
594         String spec = "controls";
595         when(mAutoAddTracker.isAdded(eq(spec))).thenReturn(true);
596         QSTile mockTile = mock(QSTile.class);
597         when(mockTile.getTileSpec()).thenReturn(spec);
598         when(mQsHost.getTiles()).thenReturn(List.of(mockTile));
599 
600         mAutoTileManager.init();
601         ArgumentCaptor<DeviceControlsController.Callback> captor =
602                 ArgumentCaptor.forClass(DeviceControlsController.Callback.class);
603 
604         verify(mDeviceControlsController).setCallback(captor.capture());
605 
606         captor.getValue().onControlsUpdate(3);
607         verify(mQsHost, never()).addTile(spec, 3);
608         verify(mAutoAddTracker, never()).setTileAdded(spec);
609     }
610 
611 
612     @Test
testEmptyArray_doesNotCrash()613     public void testEmptyArray_doesNotCrash() {
614         mContext.getOrCreateTestableResources().addOverride(
615                 R.array.config_quickSettingsAutoAdd, new String[0]);
616         createAutoTileManager(mContext).destroy();
617     }
618 
619     @Test
testMissingConfig_doesNotCrash()620     public void testMissingConfig_doesNotCrash() {
621         mContext.getOrCreateTestableResources().addOverride(
622                 R.array.config_quickSettingsAutoAdd, null);
623         createAutoTileManager(mContext).destroy();
624     }
625 
626     @Test
testUserChange_newNightDisplayListenerCreated()627     public void testUserChange_newNightDisplayListenerCreated() {
628         UserHandle newUser = UserHandle.of(1000);
629         mAutoTileManager.changeUser(newUser);
630         InOrder inOrder = inOrder(mNightDisplayListenerBuilder);
631         inOrder.verify(mNightDisplayListenerBuilder).setUser(newUser.getIdentifier());
632         inOrder.verify(mNightDisplayListenerBuilder).build();
633     }
634 
635     // Will only notify if it's listening
changeValue(String key, int value)636     private void changeValue(String key, int value) {
637         mSecureSettings.putIntForUser(key, value, USER);
638         TestableLooper.get(this).processAllMessages();
639     }
640 }
641