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