1 /*
2  * Copyright (C) 20019 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.server;
18 
19 import static android.Manifest.permission.MODIFY_DAY_NIGHT_MODE;
20 import static android.app.UiModeManager.MODE_NIGHT_AUTO;
21 import static android.app.UiModeManager.MODE_NIGHT_CUSTOM;
22 import static android.app.UiModeManager.MODE_NIGHT_CUSTOM_TYPE_BEDTIME;
23 import static android.app.UiModeManager.MODE_NIGHT_CUSTOM_TYPE_SCHEDULE;
24 import static android.app.UiModeManager.MODE_NIGHT_CUSTOM_TYPE_UNKNOWN;
25 import static android.app.UiModeManager.MODE_NIGHT_NO;
26 import static android.app.UiModeManager.MODE_NIGHT_YES;
27 import static android.app.UiModeManager.PROJECTION_TYPE_ALL;
28 import static android.app.UiModeManager.PROJECTION_TYPE_AUTOMOTIVE;
29 import static android.app.UiModeManager.PROJECTION_TYPE_NONE;
30 
31 import static com.android.server.UiModeManagerService.SUPPORTED_NIGHT_MODE_CUSTOM_TYPES;
32 
33 import static com.google.common.truth.Truth.assertThat;
34 
35 import static junit.framework.TestCase.assertFalse;
36 import static junit.framework.TestCase.assertTrue;
37 
38 import static org.hamcrest.Matchers.contains;
39 import static org.hamcrest.Matchers.empty;
40 import static org.junit.Assert.assertEquals;
41 import static org.junit.Assert.assertThat;
42 import static org.mockito.ArgumentMatchers.any;
43 import static org.mockito.ArgumentMatchers.anyInt;
44 import static org.mockito.ArgumentMatchers.anyLong;
45 import static org.mockito.ArgumentMatchers.anyString;
46 import static org.mockito.ArgumentMatchers.eq;
47 import static org.mockito.ArgumentMatchers.notNull;
48 import static org.mockito.ArgumentMatchers.nullable;
49 import static org.mockito.BDDMockito.given;
50 import static org.mockito.Mockito.atLeast;
51 import static org.mockito.Mockito.atLeastOnce;
52 import static org.mockito.Mockito.doAnswer;
53 import static org.mockito.Mockito.doReturn;
54 import static org.mockito.Mockito.doThrow;
55 import static org.mockito.Mockito.mock;
56 import static org.mockito.Mockito.never;
57 import static org.mockito.Mockito.spy;
58 import static org.mockito.Mockito.times;
59 import static org.mockito.Mockito.verify;
60 import static org.mockito.Mockito.verifyNoMoreInteractions;
61 import static org.mockito.Mockito.verifyZeroInteractions;
62 import static org.mockito.Mockito.when;
63 import static org.testng.Assert.assertThrows;
64 
65 import android.Manifest;
66 import android.app.Activity;
67 import android.app.AlarmManager;
68 import android.app.IOnProjectionStateChangedListener;
69 import android.app.IUiModeManager;
70 import android.content.BroadcastReceiver;
71 import android.content.Context;
72 import android.content.Intent;
73 import android.content.IntentFilter;
74 import android.content.pm.PackageManager;
75 import android.content.res.Configuration;
76 import android.content.res.Resources;
77 import android.os.Bundle;
78 import android.os.Handler;
79 import android.os.IBinder;
80 import android.os.PowerManager;
81 import android.os.PowerManagerInternal;
82 import android.os.PowerSaveState;
83 import android.os.Process;
84 import android.os.RemoteException;
85 import android.os.UserHandle;
86 import android.provider.Settings;
87 import android.test.mock.MockContentResolver;
88 import android.testing.AndroidTestingRunner;
89 import android.testing.TestableLooper;
90 
91 import com.android.internal.util.test.FakeSettingsProvider;
92 import com.android.server.twilight.TwilightListener;
93 import com.android.server.twilight.TwilightManager;
94 import com.android.server.twilight.TwilightState;
95 import com.android.server.wm.WindowManagerInternal;
96 
97 import org.junit.Before;
98 import org.junit.Ignore;
99 import org.junit.Test;
100 import org.junit.runner.RunWith;
101 import org.mockito.ArgumentCaptor;
102 import org.mockito.Captor;
103 import org.mockito.Mock;
104 import org.mockito.Spy;
105 
106 import java.time.LocalDateTime;
107 import java.time.LocalTime;
108 import java.time.ZoneId;
109 import java.util.List;
110 import java.util.function.Consumer;
111 
112 @RunWith(AndroidTestingRunner.class)
113 @TestableLooper.RunWithLooper
114 public class UiModeManagerServiceTest extends UiServiceTestCase {
115     private static final String PACKAGE_NAME = "Diane Coffee";
116     private UiModeManagerService mUiManagerService;
117     private IUiModeManager mService;
118     private MockContentResolver mContentResolver;
119     @Mock
120     private WindowManagerInternal mWindowManager;
121     @Mock
122     private Context mContext;
123     @Mock
124     private Resources mResources;
125     @Mock
126     private TwilightManager mTwilightManager;
127     @Mock
128     private PowerManager.WakeLock mWakeLock;
129     @Mock
130     private AlarmManager mAlarmManager;
131     @Mock
132     private PowerManager mPowerManager;
133     @Mock
134     private TwilightState mTwilightState;
135     @Mock
136     PowerManagerInternal mLocalPowerManager;
137     @Mock
138     private PackageManager mPackageManager;
139     @Mock
140     private IBinder mBinder;
141     @Spy
142     private TestInjector mInjector;
143     @Captor
144     private ArgumentCaptor<Intent> mOrderedBroadcastIntent;
145     @Captor
146     private ArgumentCaptor<BroadcastReceiver> mOrderedBroadcastReceiver;
147 
148     private BroadcastReceiver mScreenOffCallback;
149     private BroadcastReceiver mTimeChangedCallback;
150     private BroadcastReceiver mDockStateChangedCallback;
151     private AlarmManager.OnAlarmListener mCustomListener;
152     private Consumer<PowerSaveState> mPowerSaveConsumer;
153     private TwilightListener mTwilightListener;
154 
155     @Before
setUp()156     public void setUp() {
157         when(mContext.checkCallingOrSelfPermission(anyString()))
158                 .thenReturn(PackageManager.PERMISSION_GRANTED);
159         doAnswer(inv -> {
160             mTwilightListener = (TwilightListener) inv.getArgument(0);
161             return null;
162         }).when(mTwilightManager).registerListener(any(), any());
163         doAnswer(inv -> {
164             mPowerSaveConsumer = (Consumer<PowerSaveState>) inv.getArgument(1);
165             return null;
166         }).when(mLocalPowerManager).registerLowPowerModeObserver(anyInt(), any());
167         when(mLocalPowerManager.getLowPowerState(anyInt()))
168                 .thenReturn(new PowerSaveState.Builder().setBatterySaverEnabled(false).build());
169         when(mContext.getResources()).thenReturn(mResources);
170         when(mResources.getString(com.android.internal.R.string.config_somnambulatorComponent))
171                 .thenReturn("somnambulator");
172         mContentResolver = new MockContentResolver();
173         mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
174         when(mContext.getContentResolver()).thenReturn(mContentResolver);
175         when(mContext.getPackageManager()).thenReturn(mPackageManager);
176         when(mPowerManager.isInteractive()).thenReturn(true);
177         when(mPowerManager.newWakeLock(anyInt(), anyString())).thenReturn(mWakeLock);
178         when(mTwilightManager.getLastTwilightState()).thenReturn(mTwilightState);
179         when(mTwilightState.isNight()).thenReturn(true);
180         when(mContext.registerReceiver(notNull(), notNull())).then(inv -> {
181             IntentFilter filter = inv.getArgument(1);
182             if (filter.hasAction(Intent.ACTION_TIMEZONE_CHANGED)) {
183                 mTimeChangedCallback = inv.getArgument(0);
184             }
185             if (filter.hasAction(Intent.ACTION_SCREEN_OFF)) {
186                 mScreenOffCallback = inv.getArgument(0);
187             }
188             if (filter.hasAction(Intent.ACTION_DOCK_EVENT)) {
189                 mDockStateChangedCallback = inv.getArgument(0);
190             }
191             return null;
192         });
193         doAnswer(inv -> {
194             mCustomListener = inv.getArgument(3);
195             return null;
196         }).when(mAlarmManager).setExact(anyInt(), anyLong(), anyString(),
197                 any(AlarmManager.OnAlarmListener.class), any(Handler.class));
198 
199         doAnswer(inv -> {
200             mCustomListener = () -> {};
201             return null;
202         }).when(mAlarmManager).cancel(eq(mCustomListener));
203         when(mContext.getSystemService(eq(Context.POWER_SERVICE)))
204                 .thenReturn(mPowerManager);
205         when(mContext.getSystemService(PowerManager.class)).thenReturn(mPowerManager);
206         when(mContext.getSystemService(eq(Context.ALARM_SERVICE)))
207                 .thenReturn(mAlarmManager);
208         addLocalService(WindowManagerInternal.class, mWindowManager);
209         addLocalService(PowerManagerInternal.class, mLocalPowerManager);
210         addLocalService(TwilightManager.class, mTwilightManager);
211 
212         mInjector = spy(new TestInjector());
213         mUiManagerService = new UiModeManagerService(mContext, /* setupWizardComplete= */ true,
214                 mTwilightManager, mInjector);
215         try {
216             mUiManagerService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
217         } catch (SecurityException e) {/* ignore for permission denial */}
218         mService = mUiManagerService.getService();
219     }
220 
addLocalService(Class<T> clazz, T service)221     private <T> void addLocalService(Class<T> clazz, T service) {
222         LocalServices.removeServiceForTest(clazz);
223         LocalServices.addService(clazz, service);
224     }
225 
226     @Ignore // b/152719290 - Fails on stage-aosp-master
227     @Test
setNightModeActivated_overridesFunctionCorrectly()228     public void setNightModeActivated_overridesFunctionCorrectly() throws RemoteException {
229         // set up
230         when(mPowerManager.isInteractive()).thenReturn(false);
231         mService.setNightMode(MODE_NIGHT_NO);
232         assertFalse(mUiManagerService.getConfiguration().isNightModeActive());
233 
234         // assume it is day time
235         doReturn(false).when(mTwilightState).isNight();
236 
237         // set mode to auto
238         mService.setNightMode(MODE_NIGHT_AUTO);
239 
240         // set night mode on overriding current config
241         mService.setNightModeActivated(true);
242 
243         assertTrue(mUiManagerService.getConfiguration().isNightModeActive());
244 
245         // now it is night time
246         doReturn(true).when(mTwilightState).isNight();
247         mTwilightListener.onTwilightStateChanged(mTwilightState);
248 
249         assertTrue(mUiManagerService.getConfiguration().isNightModeActive());
250 
251         // now it is next day mid day
252         doReturn(false).when(mTwilightState).isNight();
253         mTwilightListener.onTwilightStateChanged(mTwilightState);
254 
255         assertFalse(mUiManagerService.getConfiguration().isNightModeActive());
256     }
257 
258     @Test
setNightModeActivated_true_withCustomModeBedtime_shouldOverrideNightModeCorrectly()259     public void setNightModeActivated_true_withCustomModeBedtime_shouldOverrideNightModeCorrectly()
260             throws RemoteException {
261         mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
262         assertFalse(mUiManagerService.getConfiguration().isNightModeActive());
263 
264         mService.setNightModeActivated(true);
265 
266         assertThat(mUiManagerService.getConfiguration().isNightModeActive()).isTrue();
267     }
268 
269     @Test
setNightModeActivated_false_withCustomModeBedtime_shouldOverrideNightModeCorrectly()270     public void setNightModeActivated_false_withCustomModeBedtime_shouldOverrideNightModeCorrectly()
271             throws RemoteException {
272         mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
273         assertFalse(mUiManagerService.getConfiguration().isNightModeActive());
274 
275         mService.setNightModeActivated(true);
276         mService.setNightModeActivated(false);
277 
278         assertThat(mUiManagerService.getConfiguration().isNightModeActive()).isFalse();
279     }
280 
281     @Test
setAutoMode_screenOffRegistered()282     public void setAutoMode_screenOffRegistered() throws RemoteException {
283         try {
284             mService.setNightMode(MODE_NIGHT_NO);
285         } catch (SecurityException e) { /* we should ignore this update config exception*/ }
286         mService.setNightMode(MODE_NIGHT_AUTO);
287         verify(mContext, atLeastOnce()).registerReceiver(any(BroadcastReceiver.class), any());
288     }
289 
290     @Ignore // b/152719290 - Fails on stage-aosp-master
291     @Test
setAutoMode_screenOffUnRegistered()292     public void setAutoMode_screenOffUnRegistered() throws RemoteException {
293         try {
294             mService.setNightMode(MODE_NIGHT_AUTO);
295         } catch (SecurityException e) { /* we should ignore this update config exception*/ }
296         try {
297             mService.setNightMode(MODE_NIGHT_NO);
298         } catch (SecurityException e) { /*we should ignore this update config exception*/ }
299         given(mContext.registerReceiver(any(), any())).willThrow(SecurityException.class);
300         verify(mContext, atLeastOnce()).unregisterReceiver(any(BroadcastReceiver.class));
301     }
302 
303     @Test
setNightModeCustomType_bedtime_shouldNotActivateNightMode()304     public void setNightModeCustomType_bedtime_shouldNotActivateNightMode() throws RemoteException {
305         try {
306             mService.setNightMode(MODE_NIGHT_NO);
307         } catch (SecurityException e) { /* we should ignore this update config exception*/ }
308         mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
309 
310         assertThat(isNightModeActivated()).isFalse();
311     }
312 
313     @Test
setNightModeCustomType_noPermission_shouldThrow()314     public void setNightModeCustomType_noPermission_shouldThrow() throws RemoteException {
315         when(mContext.checkCallingOrSelfPermission(eq(MODIFY_DAY_NIGHT_MODE)))
316                 .thenReturn(PackageManager.PERMISSION_DENIED);
317 
318         assertThrows(SecurityException.class,
319                 () -> mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME));
320     }
321 
322     @Test
setNightModeCustomType_customTypeUnknown_shouldThrow()323     public void setNightModeCustomType_customTypeUnknown_shouldThrow() throws RemoteException {
324         assertThrows(IllegalArgumentException.class,
325                 () -> mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_UNKNOWN));
326     }
327 
328     @Test
setNightModeCustomType_customTypeUnsupported_shouldThrow()329     public void setNightModeCustomType_customTypeUnsupported_shouldThrow() throws RemoteException {
330         assertThrows(IllegalArgumentException.class,
331                 () -> {
332                     int maxSupportedCustomType = 0;
333                     for (Integer supportedType : SUPPORTED_NIGHT_MODE_CUSTOM_TYPES) {
334                         maxSupportedCustomType = Math.max(maxSupportedCustomType, supportedType);
335                     }
336                     mService.setNightModeCustomType(maxSupportedCustomType + 1);
337                 });
338     }
339 
340     @Test
setNightModeCustomType_bedtime_shouldHaveNoScreenOffRegistered()341     public void setNightModeCustomType_bedtime_shouldHaveNoScreenOffRegistered()
342             throws RemoteException {
343         try {
344             mService.setNightMode(MODE_NIGHT_NO);
345         } catch (SecurityException e) { /* we should ignore this update config exception*/ }
346         mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
347         ArgumentCaptor<IntentFilter> intentFiltersCaptor = ArgumentCaptor.forClass(
348                 IntentFilter.class);
349         verify(mContext, atLeastOnce()).registerReceiver(any(BroadcastReceiver.class),
350                 intentFiltersCaptor.capture());
351 
352         List<IntentFilter> intentFilters = intentFiltersCaptor.getAllValues();
353         for (IntentFilter intentFilter : intentFilters) {
354             assertThat(intentFilter.hasAction(Intent.ACTION_SCREEN_OFF)).isFalse();
355         }
356     }
357 
358     @Test
setNightModeActivated_fromNoToYesAndBack()359     public void setNightModeActivated_fromNoToYesAndBack() throws RemoteException {
360         mService.setNightMode(MODE_NIGHT_NO);
361         mService.setNightModeActivated(true);
362         assertTrue(isNightModeActivated());
363         mService.setNightModeActivated(false);
364         assertFalse(isNightModeActivated());
365     }
366 
367     @Test
setNightModeActivated_permissionToChangeOtherUsers()368     public void setNightModeActivated_permissionToChangeOtherUsers() throws RemoteException {
369         SystemService.TargetUser user = mock(SystemService.TargetUser.class);
370         doReturn(9).when(user).getUserIdentifier();
371         mUiManagerService.onUserSwitching(user, user);
372         when(mContext.checkCallingOrSelfPermission(
373                 eq(Manifest.permission.INTERACT_ACROSS_USERS)))
374                 .thenReturn(PackageManager.PERMISSION_DENIED);
375         assertFalse(mService.setNightModeActivated(true));
376     }
377 
378     @Test
setNightModeActivatedForCustomMode_customTypeBedtime_withParamOnAndBedtime_shouldActivate()379     public void setNightModeActivatedForCustomMode_customTypeBedtime_withParamOnAndBedtime_shouldActivate()
380             throws RemoteException {
381         mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
382         mService.setNightModeActivatedForCustomMode(
383                 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
384 
385         assertThat(isNightModeActivated()).isTrue();
386     }
387 
388     @Test
setNightModeActivatedForCustomMode_customTypeBedtime_withParamOffAndBedtime_shouldDeactivate()389     public void setNightModeActivatedForCustomMode_customTypeBedtime_withParamOffAndBedtime_shouldDeactivate()
390             throws RemoteException {
391         mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
392         mService.setNightModeActivatedForCustomMode(
393                 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, false /* active */);
394 
395         assertThat(isNightModeActivated()).isFalse();
396     }
397 
398     @Test
setNightModeActivatedForCustomMode_customTypeBedtime_withParamOnAndSchedule_shouldNotActivate()399     public void setNightModeActivatedForCustomMode_customTypeBedtime_withParamOnAndSchedule_shouldNotActivate()
400             throws RemoteException {
401         mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
402         mService.setNightModeActivatedForCustomMode(
403                 MODE_NIGHT_CUSTOM_TYPE_SCHEDULE, true /* active */);
404 
405         assertThat(isNightModeActivated()).isFalse();
406     }
407 
408     @Test
setNightModeActivatedForCustomMode_customTypeSchedule_withParamOnAndBedtime_shouldNotActivate()409     public void setNightModeActivatedForCustomMode_customTypeSchedule_withParamOnAndBedtime_shouldNotActivate()
410             throws RemoteException {
411         mService.setNightMode(MODE_NIGHT_CUSTOM);
412         mService.setNightModeActivatedForCustomMode(
413                 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
414 
415         assertThat(isNightModeActivated()).isFalse();
416     }
417 
418     @Test
setNightModeActivatedForCustomMode_customTypeSchedule_withParamOnAndBedtime_thenCustomTypeBedtime_shouldActivate()419     public void setNightModeActivatedForCustomMode_customTypeSchedule_withParamOnAndBedtime_thenCustomTypeBedtime_shouldActivate()
420             throws RemoteException {
421         mService.setNightMode(MODE_NIGHT_CUSTOM);
422         mService.setNightModeActivatedForCustomMode(
423                 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
424 
425         mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
426 
427         assertThat(isNightModeActivated()).isTrue();
428     }
429 
430     @Test
setNightModeActivatedForCustomMode_customTypeBedtime_withParamOnAndBedtime_thenCustomTypeSchedule_shouldKeepNightModeActivate()431     public void setNightModeActivatedForCustomMode_customTypeBedtime_withParamOnAndBedtime_thenCustomTypeSchedule_shouldKeepNightModeActivate()
432             throws RemoteException {
433         mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
434         mService.setNightModeActivatedForCustomMode(
435                 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
436 
437         mService.setNightMode(MODE_NIGHT_CUSTOM);
438         LocalTime now = LocalTime.now();
439         mService.setCustomNightModeStart(now.plusHours(1L).toNanoOfDay() / 1000);
440         mService.setCustomNightModeEnd(now.plusHours(2L).toNanoOfDay() / 1000);
441 
442         assertThat(isNightModeActivated()).isTrue();
443     }
444 
445     @Test
setNightModeActivatedForCustomMode_customTypeBedtime_withParamOnAndBedtime_thenCustomTypeScheduleAndScreenOff_shouldDeactivateNightMode()446     public void setNightModeActivatedForCustomMode_customTypeBedtime_withParamOnAndBedtime_thenCustomTypeScheduleAndScreenOff_shouldDeactivateNightMode()
447             throws RemoteException {
448         mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
449         mService.setNightModeActivatedForCustomMode(
450                 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
451 
452         mService.setNightMode(MODE_NIGHT_CUSTOM);
453         LocalTime now = LocalTime.now();
454         mService.setCustomNightModeStart(now.plusHours(1L).toNanoOfDay() / 1000);
455         mService.setCustomNightModeEnd(now.plusHours(2L).toNanoOfDay() / 1000);
456         mScreenOffCallback.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF));
457 
458         assertThat(isNightModeActivated()).isFalse();
459     }
460 
461     @Test
autoNightModeSwitch_batterySaverOn()462     public void autoNightModeSwitch_batterySaverOn() throws RemoteException {
463         mService.setNightMode(MODE_NIGHT_NO);
464         when(mTwilightState.isNight()).thenReturn(false);
465         mService.setNightMode(MODE_NIGHT_AUTO);
466 
467         // night NO
468         assertFalse(isNightModeActivated());
469 
470         mPowerSaveConsumer.accept(
471                 new PowerSaveState.Builder().setBatterySaverEnabled(true).build());
472 
473         // night YES
474         assertTrue(isNightModeActivated());
475     }
476 
477     @Test
nightModeCustomBedtime_batterySaverOn_notInBedtime_shouldActivateNightMode()478     public void nightModeCustomBedtime_batterySaverOn_notInBedtime_shouldActivateNightMode()
479             throws RemoteException {
480         mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
481 
482         mPowerSaveConsumer.accept(
483                 new PowerSaveState.Builder().setBatterySaverEnabled(true).build());
484 
485         assertThat(isNightModeActivated()).isTrue();
486     }
487 
488     @Test
nightModeCustomBedtime_batterySaverOn_afterBedtime_shouldKeepNightModeActivated()489     public void nightModeCustomBedtime_batterySaverOn_afterBedtime_shouldKeepNightModeActivated()
490             throws RemoteException {
491         mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
492         mPowerSaveConsumer.accept(
493                 new PowerSaveState.Builder().setBatterySaverEnabled(true).build());
494 
495         mService.setNightModeActivatedForCustomMode(
496                 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, false /* active */);
497 
498         assertThat(isNightModeActivated()).isTrue();
499     }
500 
501     @Test
nightModeBedtime_duringBedtime_batterySaverOnThenOff_shouldKeepNightModeActivated()502     public void nightModeBedtime_duringBedtime_batterySaverOnThenOff_shouldKeepNightModeActivated()
503             throws RemoteException {
504         mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
505         mService.setNightModeActivatedForCustomMode(
506                 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
507 
508         mPowerSaveConsumer.accept(
509                 new PowerSaveState.Builder().setBatterySaverEnabled(true).build());
510         mPowerSaveConsumer.accept(
511                 new PowerSaveState.Builder().setBatterySaverEnabled(false).build());
512 
513         assertThat(isNightModeActivated()).isTrue();
514     }
515 
516     @Test
nightModeCustomBedtime_duringBedtime_batterySaverOnThenOff_finallyAfterBedtime_shouldDeactivateNightMode()517     public void nightModeCustomBedtime_duringBedtime_batterySaverOnThenOff_finallyAfterBedtime_shouldDeactivateNightMode()
518             throws RemoteException {
519         mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
520         mService.setNightModeActivatedForCustomMode(
521                 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
522         mPowerSaveConsumer.accept(
523                 new PowerSaveState.Builder().setBatterySaverEnabled(true).build());
524         mPowerSaveConsumer.accept(
525                 new PowerSaveState.Builder().setBatterySaverEnabled(false).build());
526 
527         mService.setNightModeActivatedForCustomMode(
528                 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, false /* active */);
529 
530         assertThat(isNightModeActivated()).isFalse();
531     }
532 
533     @Test
nightModeCustomBedtime_duringBedtime_changeModeToNo_shouldDeactivateNightMode()534     public void nightModeCustomBedtime_duringBedtime_changeModeToNo_shouldDeactivateNightMode()
535             throws RemoteException {
536         mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
537         mService.setNightModeActivatedForCustomMode(
538                 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
539 
540         mService.setNightMode(MODE_NIGHT_NO);
541 
542         assertThat(isNightModeActivated()).isFalse();
543     }
544 
545     @Test
nightModeCustomBedtime_duringBedtime_changeModeToNoAndThenExitBedtime_shouldKeepNightModeDeactivated()546     public void nightModeCustomBedtime_duringBedtime_changeModeToNoAndThenExitBedtime_shouldKeepNightModeDeactivated()
547             throws RemoteException {
548         mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
549         mService.setNightModeActivatedForCustomMode(
550                 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
551         mService.setNightMode(MODE_NIGHT_NO);
552 
553         mService.setNightModeActivatedForCustomMode(
554                 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, false /* active */);
555 
556         assertThat(isNightModeActivated()).isFalse();
557     }
558 
559     @Test
nightModeCustomBedtime_duringBedtime_changeModeToYes_shouldKeepNightModeActivated()560     public void nightModeCustomBedtime_duringBedtime_changeModeToYes_shouldKeepNightModeActivated()
561             throws RemoteException {
562         mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
563         mService.setNightModeActivatedForCustomMode(
564                 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
565 
566         mService.setNightMode(MODE_NIGHT_YES);
567 
568         assertThat(isNightModeActivated()).isTrue();
569     }
570 
571     @Test
nightModeCustomBedtime_duringBedtime_changeModeToYesAndThenExitBedtime_shouldKeepNightModeActivated()572     public void nightModeCustomBedtime_duringBedtime_changeModeToYesAndThenExitBedtime_shouldKeepNightModeActivated()
573             throws RemoteException {
574         mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
575         mService.setNightModeActivatedForCustomMode(
576                 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
577 
578         mService.setNightMode(MODE_NIGHT_YES);
579         mService.setNightModeActivatedForCustomMode(
580                 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, false /* active */);
581 
582         assertThat(isNightModeActivated()).isTrue();
583     }
584 
585     @Test
nightModeNo_duringBedtime_shouldKeepNightModeDeactivated()586     public void nightModeNo_duringBedtime_shouldKeepNightModeDeactivated()
587             throws RemoteException {
588         mService.setNightMode(MODE_NIGHT_NO);
589 
590         mService.setNightModeActivatedForCustomMode(
591                 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
592 
593         assertThat(isNightModeActivated()).isFalse();
594     }
595 
596     @Test
nightModeNo_thenChangeToCustomTypeBedtimeAndActivate_shouldActivateNightMode()597     public void nightModeNo_thenChangeToCustomTypeBedtimeAndActivate_shouldActivateNightMode()
598             throws RemoteException {
599         mService.setNightMode(MODE_NIGHT_NO);
600 
601         mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
602         mService.setNightModeActivatedForCustomMode(
603                 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
604 
605         assertThat(isNightModeActivated()).isTrue();
606     }
607 
608     @Test
nightModeYes_thenChangeToCustomTypeBedtime_shouldDeactivateNightMode()609     public void nightModeYes_thenChangeToCustomTypeBedtime_shouldDeactivateNightMode()
610             throws RemoteException {
611         mService.setNightMode(MODE_NIGHT_YES);
612 
613         mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
614 
615         assertThat(isNightModeActivated()).isFalse();
616     }
617 
618     @Test
nightModeYes_thenChangeToCustomTypeBedtimeAndActivate_shouldActivateNightMode()619     public void nightModeYes_thenChangeToCustomTypeBedtimeAndActivate_shouldActivateNightMode()
620             throws RemoteException {
621         mService.setNightMode(MODE_NIGHT_YES);
622 
623         mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
624         mService.setNightModeActivatedForCustomMode(
625                 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
626 
627         assertThat(isNightModeActivated()).isTrue();
628     }
629 
630     @Test
nightModeAuto_thenChangeToCustomTypeBedtime_notInBedtime_shouldDeactivateNightMode()631     public void nightModeAuto_thenChangeToCustomTypeBedtime_notInBedtime_shouldDeactivateNightMode()
632             throws RemoteException {
633         // set mode to auto
634         mService.setNightMode(MODE_NIGHT_AUTO);
635         mService.setNightModeActivated(true);
636         // now it is night time
637         doReturn(true).when(mTwilightState).isNight();
638         mTwilightListener.onTwilightStateChanged(mTwilightState);
639 
640         mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
641 
642         assertThat(isNightModeActivated()).isFalse();
643     }
644 
645     @Test
nightModeAuto_thenChangeToCustomTypeBedtime_duringBedtime_shouldActivateNightMode()646     public void nightModeAuto_thenChangeToCustomTypeBedtime_duringBedtime_shouldActivateNightMode()
647             throws RemoteException {
648         // set mode to auto
649         mService.setNightMode(MODE_NIGHT_AUTO);
650         mService.setNightModeActivated(true);
651         // now it is night time
652         doReturn(true).when(mTwilightState).isNight();
653         mTwilightListener.onTwilightStateChanged(mTwilightState);
654 
655         mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
656         mService.setNightModeActivatedForCustomMode(
657                 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
658 
659         assertThat(isNightModeActivated()).isTrue();
660     }
661 
662     @Test
setAutoMode_clearCache()663     public void setAutoMode_clearCache() throws RemoteException {
664         try {
665             mService.setNightMode(MODE_NIGHT_AUTO);
666         } catch (SecurityException e) { /* we should ignore this update config exception*/ }
667         try {
668             mService.setNightMode(MODE_NIGHT_NO);
669         } catch (SecurityException e) { /* we should ignore this update config exception*/ }
670         verify(mWindowManager).clearSnapshotCache();
671     }
672 
673     @Test
setNightModeActive_fromNightModeYesToNoWhenFalse()674     public void setNightModeActive_fromNightModeYesToNoWhenFalse() throws RemoteException {
675         try {
676             mService.setNightMode(MODE_NIGHT_YES);
677         } catch (SecurityException e) { /* we should ignore this update config exception*/ }
678         try {
679             mService.setNightModeActivated(false);
680         } catch (SecurityException e) { /* we should ignore this update config exception*/ }
681         assertEquals(MODE_NIGHT_NO, mService.getNightMode());
682     }
683 
684     @Test
setNightModeActive_fromNightModeNoToYesWhenTrue()685     public void setNightModeActive_fromNightModeNoToYesWhenTrue() throws RemoteException {
686         try {
687             mService.setNightMode(MODE_NIGHT_NO);
688         } catch (SecurityException e) { /* we should ignore this update config exception*/ }
689         try {
690             mService.setNightModeActivated(true);
691         } catch (SecurityException e) { /* we should ignore this update config exception*/ }
692         assertEquals(MODE_NIGHT_YES, mService.getNightMode());
693     }
694 
695     @Test
setNightModeActive_autoNightModeNoChanges()696     public void setNightModeActive_autoNightModeNoChanges() throws RemoteException {
697         try {
698             mService.setNightMode(MODE_NIGHT_AUTO);
699         } catch (SecurityException e) { /* we should ignore this update config exception*/ }
700         try {
701             mService.setNightModeActivated(true);
702         } catch (SecurityException e) { /* we should ignore this update config exception*/ }
703         assertEquals(MODE_NIGHT_AUTO, mService.getNightMode());
704     }
705 
706     @Test
getNightModeCustomType_nightModeNo_shouldReturnUnknown()707     public void getNightModeCustomType_nightModeNo_shouldReturnUnknown() throws RemoteException {
708         try {
709             mService.setNightMode(MODE_NIGHT_NO);
710         } catch (SecurityException e) { /* we should ignore this update config exception*/ }
711 
712         assertThat(mService.getNightModeCustomType()).isEqualTo(MODE_NIGHT_CUSTOM_TYPE_UNKNOWN);
713     }
714 
715     @Test
getNightModeCustomType_nightModeYes_shouldReturnUnknown()716     public void getNightModeCustomType_nightModeYes_shouldReturnUnknown() throws RemoteException {
717         try {
718             mService.setNightMode(MODE_NIGHT_YES);
719         } catch (SecurityException e) { /* we should ignore this update config exception*/ }
720 
721         assertThat(mService.getNightModeCustomType()).isEqualTo(MODE_NIGHT_CUSTOM_TYPE_UNKNOWN);
722     }
723 
724     @Test
getNightModeCustomType_nightModeAuto_shouldReturnUnknown()725     public void getNightModeCustomType_nightModeAuto_shouldReturnUnknown() throws RemoteException {
726         try {
727             mService.setNightMode(MODE_NIGHT_AUTO);
728         } catch (SecurityException e) { /* we should ignore this update config exception*/ }
729 
730         assertThat(mService.getNightModeCustomType()).isEqualTo(MODE_NIGHT_CUSTOM_TYPE_UNKNOWN);
731     }
732 
733     @Test
getNightModeCustomType_nightModeCustom_shouldReturnSchedule()734     public void getNightModeCustomType_nightModeCustom_shouldReturnSchedule()
735             throws RemoteException {
736         try {
737             mService.setNightMode(MODE_NIGHT_CUSTOM);
738         } catch (SecurityException e) { /* we should ignore this update config exception*/ }
739 
740         assertThat(mService.getNightModeCustomType()).isEqualTo(MODE_NIGHT_CUSTOM_TYPE_SCHEDULE);
741     }
742 
743     @Test
getNightModeCustomType_nightModeCustomBedtime_shouldReturnBedtime()744     public void getNightModeCustomType_nightModeCustomBedtime_shouldReturnBedtime()
745             throws RemoteException {
746         try {
747             mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
748         } catch (SecurityException e) { /* we should ignore this update config exception*/ }
749 
750         assertThat(mService.getNightModeCustomType()).isEqualTo(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
751     }
752 
753     @Test
getNightModeCustomType_permissionNotGranted_shouldThrow()754     public void getNightModeCustomType_permissionNotGranted_shouldThrow()
755             throws RemoteException {
756         when(mContext.checkCallingOrSelfPermission(eq(MODIFY_DAY_NIGHT_MODE)))
757                 .thenReturn(PackageManager.PERMISSION_DENIED);
758 
759         assertThrows(SecurityException.class, () -> mService.getNightModeCustomType());
760     }
761 
762     @Test
isNightModeActive_nightModeYes()763     public void isNightModeActive_nightModeYes() throws RemoteException {
764         try {
765             mService.setNightMode(MODE_NIGHT_YES);
766         } catch (SecurityException e) { /* we should ignore this update config exception*/ }
767         assertTrue(isNightModeActivated());
768     }
769 
770     @Test
isNightModeActive_nightModeNo()771     public void isNightModeActive_nightModeNo() throws RemoteException {
772         try {
773             mService.setNightMode(MODE_NIGHT_NO);
774         } catch (SecurityException e) { /* we should ignore this update config exception*/ }
775         assertFalse(isNightModeActivated());
776     }
777 
778     @Test
customTime_darkThemeOn()779     public void customTime_darkThemeOn() throws RemoteException {
780         LocalTime now = LocalTime.now();
781         mService.setNightMode(MODE_NIGHT_NO);
782         mService.setCustomNightModeStart(now.minusHours(1L).toNanoOfDay() / 1000);
783         mService.setCustomNightModeEnd(now.plusHours(1L).toNanoOfDay() / 1000);
784         mService.setNightMode(MODE_NIGHT_CUSTOM);
785         mScreenOffCallback.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF));
786         assertTrue(isNightModeActivated());
787     }
788 
789     @Test
customTime_darkThemeOff()790     public void customTime_darkThemeOff() throws RemoteException {
791         LocalTime now = LocalTime.now();
792         mService.setNightMode(MODE_NIGHT_YES);
793         mService.setCustomNightModeStart(now.plusHours(1L).toNanoOfDay() / 1000);
794         mService.setCustomNightModeEnd(now.minusHours(1L).toNanoOfDay() / 1000);
795         mService.setNightMode(MODE_NIGHT_CUSTOM);
796         mScreenOffCallback.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF));
797         assertFalse(isNightModeActivated());
798     }
799 
800     @Test
customTime_darkThemeOff_afterStartEnd()801     public void customTime_darkThemeOff_afterStartEnd() throws RemoteException {
802         LocalTime now = LocalTime.now();
803         mService.setNightMode(MODE_NIGHT_YES);
804         mService.setCustomNightModeStart(now.plusHours(1L).toNanoOfDay() / 1000);
805         mService.setCustomNightModeEnd(now.plusHours(2L).toNanoOfDay() / 1000);
806         mService.setNightMode(MODE_NIGHT_CUSTOM);
807         mScreenOffCallback.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF));
808         assertFalse(isNightModeActivated());
809     }
810 
811     @Test
customTime_darkThemeOn_afterStartEnd()812     public void customTime_darkThemeOn_afterStartEnd() throws RemoteException {
813         LocalTime now = LocalTime.now();
814         mService.setNightMode(MODE_NIGHT_YES);
815         mService.setCustomNightModeStart(now.plusHours(1L).toNanoOfDay() / 1000);
816         mService.setCustomNightModeEnd(now.plusHours(2L).toNanoOfDay() / 1000);
817         mService.setNightMode(MODE_NIGHT_CUSTOM);
818         mScreenOffCallback.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF));
819         assertFalse(isNightModeActivated());
820     }
821 
822 
823     @Test
customTime_darkThemeOn_beforeStartEnd()824     public void customTime_darkThemeOn_beforeStartEnd() throws RemoteException {
825         LocalTime now = LocalTime.now();
826         mService.setNightMode(MODE_NIGHT_YES);
827         mService.setCustomNightModeStart(now.minusHours(1L).toNanoOfDay() / 1000);
828         mService.setCustomNightModeEnd(now.minusHours(2L).toNanoOfDay() / 1000);
829         mService.setNightMode(MODE_NIGHT_CUSTOM);
830         mScreenOffCallback.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF));
831         assertTrue(isNightModeActivated());
832     }
833 
834     @Test
customTime_darkThemeOff_beforeStartEnd()835     public void customTime_darkThemeOff_beforeStartEnd() throws RemoteException {
836         LocalTime now = LocalTime.now();
837         mService.setNightMode(MODE_NIGHT_YES);
838         mService.setCustomNightModeStart(now.minusHours(2L).toNanoOfDay() / 1000);
839         mService.setCustomNightModeEnd(now.minusHours(1L).toNanoOfDay() / 1000);
840         mService.setNightMode(MODE_NIGHT_CUSTOM);
841         mScreenOffCallback.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF));
842         assertFalse(isNightModeActivated());
843     }
844 
845     @Test
customTIme_customAlarmSetWhenScreenTimeChanges()846     public void customTIme_customAlarmSetWhenScreenTimeChanges() throws RemoteException {
847         when(mPowerManager.isInteractive()).thenReturn(false);
848         mService.setNightMode(MODE_NIGHT_CUSTOM);
849         verify(mAlarmManager, times(1))
850                 .setExact(anyInt(), anyLong(), anyString(), any(), any());
851         mTimeChangedCallback.onReceive(mContext, new Intent(Intent.ACTION_TIME_CHANGED));
852         verify(mAlarmManager, atLeast(2))
853                 .setExact(anyInt(), anyLong(), anyString(), any(), any());
854     }
855 
856     @Test
customTime_alarmSetInTheFutureWhenOn()857     public void customTime_alarmSetInTheFutureWhenOn() throws RemoteException {
858         LocalDateTime now = LocalDateTime.now();
859         when(mPowerManager.isInteractive()).thenReturn(false);
860         mService.setNightMode(MODE_NIGHT_YES);
861         mService.setCustomNightModeStart(now.toLocalTime().minusHours(1L).toNanoOfDay() / 1000);
862         mService.setCustomNightModeEnd(now.toLocalTime().plusHours(1L).toNanoOfDay() / 1000);
863         LocalDateTime next = now.plusHours(1L);
864         final long millis = next.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
865         mService.setNightMode(MODE_NIGHT_CUSTOM);
866         verify(mAlarmManager)
867                 .setExact(anyInt(), eq(millis), anyString(), any(), any());
868     }
869 
870     @Test
customTime_appliesImmediatelyWhenScreenOff()871     public void customTime_appliesImmediatelyWhenScreenOff() throws RemoteException {
872         when(mPowerManager.isInteractive()).thenReturn(false);
873         LocalTime now = LocalTime.now();
874         mService.setNightMode(MODE_NIGHT_NO);
875         mService.setCustomNightModeStart(now.minusHours(1L).toNanoOfDay() / 1000);
876         mService.setCustomNightModeEnd(now.plusHours(1L).toNanoOfDay() / 1000);
877         mService.setNightMode(MODE_NIGHT_CUSTOM);
878         assertTrue(isNightModeActivated());
879     }
880 
881     @Test
customTime_appliesOnlyWhenScreenOff()882     public void customTime_appliesOnlyWhenScreenOff() throws RemoteException {
883         LocalTime now = LocalTime.now();
884         mService.setNightMode(MODE_NIGHT_NO);
885         mService.setCustomNightModeStart(now.minusHours(1L).toNanoOfDay() / 1000);
886         mService.setCustomNightModeEnd(now.plusHours(1L).toNanoOfDay() / 1000);
887         mService.setNightMode(MODE_NIGHT_CUSTOM);
888         assertFalse(isNightModeActivated());
889         mScreenOffCallback.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF));
890         assertTrue(isNightModeActivated());
891     }
892 
893     @Test
nightAuto_appliesOnlyWhenScreenOff()894     public void nightAuto_appliesOnlyWhenScreenOff() throws RemoteException {
895         when(mTwilightState.isNight()).thenReturn(true);
896         mService.setNightMode(MODE_NIGHT_NO);
897         mService.setNightMode(MODE_NIGHT_AUTO);
898         assertFalse(isNightModeActivated());
899         mScreenOffCallback.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF));
900         assertTrue(isNightModeActivated());
901     }
902 
isNightModeActivated()903     private boolean isNightModeActivated() {
904         return (mUiManagerService.getConfiguration().uiMode
905                 & Configuration.UI_MODE_NIGHT_YES) != 0;
906     }
907 
908     @Test
requestProjection_failsForBogusPackageName()909     public void requestProjection_failsForBogusPackageName() throws Exception {
910         when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
911                 .thenReturn(TestInjector.DEFAULT_CALLING_UID + 1);
912 
913         assertThrows(SecurityException.class, () -> mService.requestProjection(mBinder,
914                 PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME));
915         assertEquals(PROJECTION_TYPE_NONE, mService.getActiveProjectionTypes());
916     }
917 
918     @Test
requestProjection_failsIfNameNotFound()919     public void requestProjection_failsIfNameNotFound() throws Exception {
920         when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
921                 .thenThrow(new PackageManager.NameNotFoundException());
922 
923         assertThrows(SecurityException.class, () -> mService.requestProjection(mBinder,
924                 PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME));
925         assertEquals(PROJECTION_TYPE_NONE, mService.getActiveProjectionTypes());
926     }
927 
928     @Test
requestProjection_failsIfNoProjectionTypes()929     public void requestProjection_failsIfNoProjectionTypes() throws Exception {
930         when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
931                 .thenReturn(TestInjector.DEFAULT_CALLING_UID);
932 
933         assertThrows(IllegalArgumentException.class,
934                 () -> mService.requestProjection(mBinder, PROJECTION_TYPE_NONE, PACKAGE_NAME));
935         verify(mContext, never()).enforceCallingPermission(
936                 eq(Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION), any());
937         verifyZeroInteractions(mBinder);
938         assertEquals(PROJECTION_TYPE_NONE, mService.getActiveProjectionTypes());
939     }
940 
941     @Test
requestProjection_failsIfMultipleProjectionTypes()942     public void requestProjection_failsIfMultipleProjectionTypes() throws Exception {
943         when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
944                 .thenReturn(TestInjector.DEFAULT_CALLING_UID);
945 
946         // Don't use PROJECTION_TYPE_ALL because that's actually == -1 and will fail the > 0 check.
947         int multipleProjectionTypes = PROJECTION_TYPE_AUTOMOTIVE | 0x0002 | 0x0004;
948 
949         assertThrows(IllegalArgumentException.class,
950                 () -> mService.requestProjection(mBinder, multipleProjectionTypes, PACKAGE_NAME));
951         verify(mContext, never()).enforceCallingPermission(
952                 eq(Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION), any());
953         verifyZeroInteractions(mBinder);
954         assertEquals(PROJECTION_TYPE_NONE, mService.getActiveProjectionTypes());
955     }
956 
957     @Test
requestProjection_enforcesToggleAutomotiveProjectionPermission()958     public void requestProjection_enforcesToggleAutomotiveProjectionPermission() throws Exception {
959         doThrow(new SecurityException())
960                 .when(mPackageManager).getPackageUidAsUser(eq(PACKAGE_NAME), anyInt());
961 
962         assertThrows(SecurityException.class, () -> mService.requestProjection(mBinder,
963                 PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME));
964         assertEquals(PROJECTION_TYPE_NONE, mService.getActiveProjectionTypes());
965     }
966 
967     @Test
requestProjection_automotive_failsIfAlreadySetByOtherPackage()968     public void requestProjection_automotive_failsIfAlreadySetByOtherPackage() throws Exception {
969         when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
970                 .thenReturn(TestInjector.DEFAULT_CALLING_UID);
971         mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
972         assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
973 
974         String otherPackage = "Raconteurs";
975         when(mPackageManager.getPackageUidAsUser(eq(otherPackage), anyInt()))
976                 .thenReturn(TestInjector.DEFAULT_CALLING_UID);
977         assertFalse(mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, otherPackage));
978         assertThat(mService.getProjectingPackages(PROJECTION_TYPE_AUTOMOTIVE),
979                 contains(PACKAGE_NAME));
980     }
981 
982     @Test
requestProjection_failsIfCannotLinkToDeath()983     public void requestProjection_failsIfCannotLinkToDeath() throws Exception {
984         when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
985                 .thenReturn(TestInjector.DEFAULT_CALLING_UID);
986         doThrow(new RemoteException()).when(mBinder).linkToDeath(any(), anyInt());
987 
988         assertFalse(mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME));
989         assertEquals(PROJECTION_TYPE_NONE, mService.getActiveProjectionTypes());
990     }
991 
992     @Test
requestProjection()993     public void requestProjection() throws Exception {
994         when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
995                 .thenReturn(TestInjector.DEFAULT_CALLING_UID);
996         // Should work for all powers of two.
997         for (int i = 0; i < Integer.SIZE; ++i) {
998             int projectionType = 1 << i;
999             assertTrue(mService.requestProjection(mBinder, projectionType, PACKAGE_NAME));
1000             assertTrue((mService.getActiveProjectionTypes() & projectionType) != 0);
1001             assertThat(mService.getProjectingPackages(projectionType), contains(PACKAGE_NAME));
1002             // Subsequent calls should still succeed.
1003             assertTrue(mService.requestProjection(mBinder, projectionType, PACKAGE_NAME));
1004         }
1005         assertEquals(PROJECTION_TYPE_ALL, mService.getActiveProjectionTypes());
1006     }
1007 
1008     @Test
releaseProjection_failsForBogusPackageName()1009     public void releaseProjection_failsForBogusPackageName() throws Exception {
1010         when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
1011                 .thenReturn(TestInjector.DEFAULT_CALLING_UID);
1012         mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
1013         assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
1014 
1015         when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
1016                 .thenReturn(TestInjector.DEFAULT_CALLING_UID + 1);
1017 
1018         assertThrows(SecurityException.class, () -> mService.releaseProjection(
1019                 PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME));
1020         assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
1021     }
1022 
1023     @Test
releaseProjection_failsIfNameNotFound()1024     public void releaseProjection_failsIfNameNotFound() throws Exception {
1025         when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
1026                 .thenReturn(TestInjector.DEFAULT_CALLING_UID);
1027         mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
1028         assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
1029         when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
1030                 .thenThrow(new PackageManager.NameNotFoundException());
1031 
1032         assertThrows(SecurityException.class, () -> mService.releaseProjection(
1033                 PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME));
1034         assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
1035     }
1036 
1037     @Test
releaseProjection_enforcesToggleAutomotiveProjectionPermission()1038     public void releaseProjection_enforcesToggleAutomotiveProjectionPermission() throws Exception {
1039         when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
1040                 .thenReturn(TestInjector.DEFAULT_CALLING_UID);
1041         mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
1042         assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
1043         doThrow(new SecurityException()).when(mContext).enforceCallingPermission(
1044                 eq(Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION), any());
1045 
1046         // Should not be enforced for other types of projection.
1047         int nonAutomotiveProjectionType = PROJECTION_TYPE_AUTOMOTIVE * 2;
1048         mService.releaseProjection(nonAutomotiveProjectionType, PACKAGE_NAME);
1049         assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
1050 
1051         assertThrows(SecurityException.class, () -> mService.requestProjection(mBinder,
1052                 PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME));
1053         assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
1054     }
1055 
1056     @Test
releaseProjection()1057     public void releaseProjection() throws Exception {
1058         when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
1059                 .thenReturn(TestInjector.DEFAULT_CALLING_UID);
1060         requestAllPossibleProjectionTypes();
1061         assertEquals(PROJECTION_TYPE_ALL, mService.getActiveProjectionTypes());
1062 
1063         assertTrue(mService.releaseProjection(PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME));
1064         int everythingButAutomotive = PROJECTION_TYPE_ALL & ~PROJECTION_TYPE_AUTOMOTIVE;
1065         assertEquals(everythingButAutomotive, mService.getActiveProjectionTypes());
1066 
1067         for (int i = 0; i < Integer.SIZE; ++i) {
1068             int projectionType = 1 << i;
1069             assertEquals(projectionType != PROJECTION_TYPE_AUTOMOTIVE,
1070                     (boolean) mService.releaseProjection(projectionType, PACKAGE_NAME));
1071         }
1072 
1073         assertEquals(PROJECTION_TYPE_NONE, mService.getActiveProjectionTypes());
1074     }
1075 
1076     @Test
binderDeath_releasesProjection()1077     public void binderDeath_releasesProjection() throws Exception {
1078         when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
1079                 .thenReturn(TestInjector.DEFAULT_CALLING_UID);
1080         requestAllPossibleProjectionTypes();
1081         assertEquals(PROJECTION_TYPE_ALL, mService.getActiveProjectionTypes());
1082         ArgumentCaptor<IBinder.DeathRecipient> deathRecipientCaptor = ArgumentCaptor.forClass(
1083                 IBinder.DeathRecipient.class);
1084         verify(mBinder, atLeastOnce()).linkToDeath(deathRecipientCaptor.capture(), anyInt());
1085 
1086         // Wipe them out. All of them.
1087         deathRecipientCaptor.getAllValues().forEach(IBinder.DeathRecipient::binderDied);
1088         assertEquals(PROJECTION_TYPE_NONE, mService.getActiveProjectionTypes());
1089     }
1090 
1091     @Test
getActiveProjectionTypes()1092     public void getActiveProjectionTypes() throws Exception {
1093         assertEquals(PROJECTION_TYPE_NONE, mService.getActiveProjectionTypes());
1094         when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
1095                 .thenReturn(TestInjector.DEFAULT_CALLING_UID);
1096         mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
1097         assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
1098         mService.releaseProjection(PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
1099         assertEquals(PROJECTION_TYPE_NONE, mService.getActiveProjectionTypes());
1100     }
1101 
1102     @Test
getProjectingPackages()1103     public void getProjectingPackages() throws Exception {
1104         assertTrue(mService.getProjectingPackages(PROJECTION_TYPE_ALL).isEmpty());
1105         when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
1106                 .thenReturn(TestInjector.DEFAULT_CALLING_UID);
1107         mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
1108         assertEquals(1, mService.getProjectingPackages(PROJECTION_TYPE_AUTOMOTIVE).size());
1109         assertEquals(1, mService.getProjectingPackages(PROJECTION_TYPE_ALL).size());
1110         assertThat(mService.getProjectingPackages(PROJECTION_TYPE_AUTOMOTIVE),
1111                 contains(PACKAGE_NAME));
1112         assertThat(mService.getProjectingPackages(PROJECTION_TYPE_ALL), contains(PACKAGE_NAME));
1113         mService.releaseProjection(PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
1114         assertThat(mService.getProjectingPackages(PROJECTION_TYPE_ALL), empty());
1115     }
1116 
1117     @Test
addOnProjectionStateChangedListener_enforcesReadProjStatePermission()1118     public void addOnProjectionStateChangedListener_enforcesReadProjStatePermission() {
1119         doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
1120                 eq(android.Manifest.permission.READ_PROJECTION_STATE), any());
1121         IOnProjectionStateChangedListener listener = mock(IOnProjectionStateChangedListener.class);
1122 
1123         assertThrows(SecurityException.class, () -> mService.addOnProjectionStateChangedListener(
1124                 listener, PROJECTION_TYPE_ALL));
1125     }
1126 
1127     @Test
addOnProjectionStateChangedListener_callsListenerIfProjectionActive()1128     public void addOnProjectionStateChangedListener_callsListenerIfProjectionActive()
1129             throws Exception {
1130         when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
1131                 .thenReturn(TestInjector.DEFAULT_CALLING_UID);
1132         mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
1133         assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
1134 
1135         IOnProjectionStateChangedListener listener = mock(IOnProjectionStateChangedListener.class);
1136         when(listener.asBinder()).thenReturn(mBinder);  // Any binder will do
1137         mService.addOnProjectionStateChangedListener(listener, PROJECTION_TYPE_ALL);
1138         verify(listener).onProjectionStateChanged(eq(PROJECTION_TYPE_AUTOMOTIVE),
1139                 eq(List.of(PACKAGE_NAME)));
1140     }
1141 
1142     @Test
removeOnProjectionStateChangedListener_enforcesReadProjStatePermission()1143     public void removeOnProjectionStateChangedListener_enforcesReadProjStatePermission() {
1144         doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
1145                 eq(android.Manifest.permission.READ_PROJECTION_STATE), any());
1146         IOnProjectionStateChangedListener listener = mock(IOnProjectionStateChangedListener.class);
1147 
1148         assertThrows(SecurityException.class, () -> mService.removeOnProjectionStateChangedListener(
1149                 listener));
1150     }
1151 
1152     @Test
removeOnProjectionStateChangedListener()1153     public void removeOnProjectionStateChangedListener() throws Exception {
1154         IOnProjectionStateChangedListener listener = mock(IOnProjectionStateChangedListener.class);
1155         when(listener.asBinder()).thenReturn(mBinder); // Any binder will do.
1156         mService.addOnProjectionStateChangedListener(listener, PROJECTION_TYPE_ALL);
1157 
1158         mService.removeOnProjectionStateChangedListener(listener);
1159         // Now set automotive projection, should not call back.
1160         when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
1161                 .thenReturn(TestInjector.DEFAULT_CALLING_UID);
1162         mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
1163         verify(listener, never()).onProjectionStateChanged(anyInt(), any());
1164     }
1165 
1166     @Test
projectionStateChangedListener_calledWhenStateChanges()1167     public void projectionStateChangedListener_calledWhenStateChanges() throws Exception {
1168         IOnProjectionStateChangedListener listener = mock(IOnProjectionStateChangedListener.class);
1169         when(listener.asBinder()).thenReturn(mBinder); // Any binder will do.
1170         mService.addOnProjectionStateChangedListener(listener, PROJECTION_TYPE_ALL);
1171         verify(listener, atLeastOnce()).asBinder(); // Called twice during register.
1172 
1173         // No calls initially, no projection state set.
1174         verifyNoMoreInteractions(listener);
1175 
1176         // Now set automotive projection, should call back.
1177         when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
1178                 .thenReturn(TestInjector.DEFAULT_CALLING_UID);
1179         mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
1180         verify(listener).onProjectionStateChanged(eq(PROJECTION_TYPE_AUTOMOTIVE),
1181                 eq(List.of(PACKAGE_NAME)));
1182 
1183         // Subsequent calls that are noops do nothing.
1184         mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
1185         int unsetProjectionType = 0x0002;
1186         mService.releaseProjection(unsetProjectionType, PACKAGE_NAME);
1187         verifyNoMoreInteractions(listener);
1188 
1189         // Release should call back though.
1190         mService.releaseProjection(PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
1191         verify(listener).onProjectionStateChanged(eq(PROJECTION_TYPE_NONE),
1192                 eq(List.of()));
1193 
1194         // But only the first time.
1195         mService.releaseProjection(PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
1196         verifyNoMoreInteractions(listener);
1197     }
1198 
1199     @Test
projectionStateChangedListener_calledForAnyRelevantStateChange()1200     public void projectionStateChangedListener_calledForAnyRelevantStateChange() throws Exception {
1201         int fakeProjectionType = 0x0002;
1202         int otherFakeProjectionType = 0x0004;
1203         String otherPackageName = "Internet Arms";
1204         when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
1205                 .thenReturn(TestInjector.DEFAULT_CALLING_UID);
1206         when(mPackageManager.getPackageUidAsUser(eq(otherPackageName), anyInt()))
1207                 .thenReturn(TestInjector.DEFAULT_CALLING_UID);
1208         IOnProjectionStateChangedListener listener = mock(IOnProjectionStateChangedListener.class);
1209         when(listener.asBinder()).thenReturn(mBinder); // Any binder will do.
1210         IOnProjectionStateChangedListener listener2 = mock(IOnProjectionStateChangedListener.class);
1211         when(listener2.asBinder()).thenReturn(mBinder); // Any binder will do.
1212         mService.addOnProjectionStateChangedListener(listener, fakeProjectionType);
1213         mService.addOnProjectionStateChangedListener(listener2,
1214                 fakeProjectionType | otherFakeProjectionType);
1215         verify(listener, atLeastOnce()).asBinder(); // Called twice during register.
1216         verify(listener2, atLeastOnce()).asBinder(); // Called twice during register.
1217 
1218         mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
1219         verifyNoMoreInteractions(listener, listener2);
1220 
1221         // fakeProjectionType should trigger both.
1222         mService.requestProjection(mBinder, fakeProjectionType, PACKAGE_NAME);
1223         verify(listener).onProjectionStateChanged(eq(fakeProjectionType),
1224                 eq(List.of(PACKAGE_NAME)));
1225         verify(listener2).onProjectionStateChanged(eq(fakeProjectionType),
1226                 eq(List.of(PACKAGE_NAME)));
1227 
1228         // otherFakeProjectionType should only trigger the second listener.
1229         mService.requestProjection(mBinder, otherFakeProjectionType, otherPackageName);
1230         verifyNoMoreInteractions(listener);
1231         verify(listener2).onProjectionStateChanged(
1232                 eq(fakeProjectionType | otherFakeProjectionType),
1233                 eq(List.of(PACKAGE_NAME, otherPackageName)));
1234 
1235         // Turning off fakeProjectionType should trigger both again.
1236         mService.releaseProjection(fakeProjectionType, PACKAGE_NAME);
1237         verify(listener).onProjectionStateChanged(eq(PROJECTION_TYPE_NONE), eq(List.of()));
1238         verify(listener2).onProjectionStateChanged(eq(otherFakeProjectionType),
1239                 eq(List.of(otherPackageName)));
1240 
1241         // Turning off otherFakeProjectionType should only trigger the second listener.
1242         mService.releaseProjection(otherFakeProjectionType, otherPackageName);
1243         verifyNoMoreInteractions(listener);
1244         verify(listener2).onProjectionStateChanged(eq(PROJECTION_TYPE_NONE), eq(List.of()));
1245     }
1246 
1247     @Test
projectionStateChangedListener_unregisteredOnDeath()1248     public void projectionStateChangedListener_unregisteredOnDeath() throws Exception {
1249         IOnProjectionStateChangedListener listener = mock(IOnProjectionStateChangedListener.class);
1250         IBinder listenerBinder = mock(IBinder.class);
1251         when(listener.asBinder()).thenReturn(listenerBinder);
1252         mService.addOnProjectionStateChangedListener(listener, PROJECTION_TYPE_ALL);
1253         ArgumentCaptor<IBinder.DeathRecipient> listenerDeathRecipient = ArgumentCaptor.forClass(
1254                 IBinder.DeathRecipient.class);
1255         verify(listenerBinder).linkToDeath(listenerDeathRecipient.capture(), anyInt());
1256 
1257         // Now kill the binder for the listener. This should remove it from the list of listeners.
1258         listenerDeathRecipient.getValue().binderDied();
1259         when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
1260                 .thenReturn(TestInjector.DEFAULT_CALLING_UID);
1261         mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
1262         verify(listener, never()).onProjectionStateChanged(anyInt(), any());
1263     }
1264 
1265     @Test
enableCarMode_failsForBogusPackageName()1266     public void enableCarMode_failsForBogusPackageName() throws Exception {
1267         when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
1268             .thenReturn(TestInjector.DEFAULT_CALLING_UID + 1);
1269 
1270         assertThrows(SecurityException.class, () -> mService.enableCarMode(0, 0, PACKAGE_NAME));
1271         assertThat(mService.getCurrentModeType()).isNotEqualTo(Configuration.UI_MODE_TYPE_CAR);
1272     }
1273 
1274     @Test
enableCarMode_shell()1275     public void enableCarMode_shell() throws Exception {
1276         mUiManagerService = new UiModeManagerService(mContext, /* setupWizardComplete= */ true,
1277                 mTwilightManager, new TestInjector(Process.SHELL_UID));
1278         try {
1279             mUiManagerService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
1280         } catch (SecurityException e) {/* ignore for permission denial */}
1281         mService = mUiManagerService.getService();
1282 
1283         mService.enableCarMode(0, 0, PACKAGE_NAME);
1284         assertThat(mService.getCurrentModeType()).isEqualTo(Configuration.UI_MODE_TYPE_CAR);
1285     }
1286 
1287     @Test
disableCarMode_failsForBogusPackageName()1288     public void disableCarMode_failsForBogusPackageName() throws Exception {
1289         when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
1290             .thenReturn(TestInjector.DEFAULT_CALLING_UID);
1291         mService.enableCarMode(0, 0, PACKAGE_NAME);
1292         assertThat(mService.getCurrentModeType()).isEqualTo(Configuration.UI_MODE_TYPE_CAR);
1293         when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
1294             .thenReturn(TestInjector.DEFAULT_CALLING_UID + 1);
1295 
1296         assertThrows(SecurityException.class,
1297             () -> mService.disableCarModeByCallingPackage(0, PACKAGE_NAME));
1298         assertThat(mService.getCurrentModeType()).isEqualTo(Configuration.UI_MODE_TYPE_CAR);
1299 
1300         // Clean up
1301         when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
1302             .thenReturn(TestInjector.DEFAULT_CALLING_UID);
1303         mService.disableCarModeByCallingPackage(0, PACKAGE_NAME);
1304         assertThat(mService.getCurrentModeType()).isNotEqualTo(Configuration.UI_MODE_TYPE_CAR);
1305     }
1306 
1307     @Test
disableCarMode_shell()1308     public void disableCarMode_shell() throws Exception {
1309         mUiManagerService = new UiModeManagerService(mContext, /* setupWizardComplete= */ true,
1310                 mTwilightManager, new TestInjector(Process.SHELL_UID));
1311         try {
1312             mUiManagerService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
1313         } catch (SecurityException e) {/* ignore for permission denial */}
1314         mService = mUiManagerService.getService();
1315 
1316         mService.enableCarMode(0, 0, PACKAGE_NAME);
1317         assertThat(mService.getCurrentModeType()).isEqualTo(Configuration.UI_MODE_TYPE_CAR);
1318 
1319         mService.disableCarModeByCallingPackage(0, PACKAGE_NAME);
1320         assertThat(mService.getCurrentModeType()).isNotEqualTo(Configuration.UI_MODE_TYPE_CAR);
1321     }
1322 
1323     @Test
dreamWhenDocked()1324     public void dreamWhenDocked() {
1325         triggerDockIntent();
1326         verifyAndSendResultBroadcast();
1327         verify(mInjector).startDreamWhenDockedIfAppropriate(mContext);
1328     }
1329 
1330     @Test
noDreamWhenDocked_keyguardNotShowing_interactive()1331     public void noDreamWhenDocked_keyguardNotShowing_interactive() {
1332         mUiManagerService.setStartDreamImmediatelyOnDock(false);
1333         when(mWindowManager.isKeyguardShowingAndNotOccluded()).thenReturn(false);
1334         when(mPowerManager.isInteractive()).thenReturn(true);
1335 
1336         triggerDockIntent();
1337         verifyAndSendResultBroadcast();
1338         verify(mInjector, never()).startDreamWhenDockedIfAppropriate(mContext);
1339     }
1340 
1341     @Test
dreamWhenDocked_keyguardShowing_interactive()1342     public void dreamWhenDocked_keyguardShowing_interactive() {
1343         mUiManagerService.setStartDreamImmediatelyOnDock(false);
1344         when(mWindowManager.isKeyguardShowingAndNotOccluded()).thenReturn(true);
1345         when(mPowerManager.isInteractive()).thenReturn(false);
1346 
1347         triggerDockIntent();
1348         verifyAndSendResultBroadcast();
1349         verify(mInjector).startDreamWhenDockedIfAppropriate(mContext);
1350     }
1351 
1352     @Test
dreamWhenDocked_keyguardNotShowing_notInteractive()1353     public void dreamWhenDocked_keyguardNotShowing_notInteractive() {
1354         mUiManagerService.setStartDreamImmediatelyOnDock(false);
1355         when(mWindowManager.isKeyguardShowingAndNotOccluded()).thenReturn(false);
1356         when(mPowerManager.isInteractive()).thenReturn(false);
1357 
1358         triggerDockIntent();
1359         verifyAndSendResultBroadcast();
1360         verify(mInjector).startDreamWhenDockedIfAppropriate(mContext);
1361     }
1362 
1363     @Test
dreamWhenDocked_keyguardShowing_notInteractive()1364     public void dreamWhenDocked_keyguardShowing_notInteractive() {
1365         mUiManagerService.setStartDreamImmediatelyOnDock(false);
1366         when(mWindowManager.isKeyguardShowingAndNotOccluded()).thenReturn(true);
1367         when(mPowerManager.isInteractive()).thenReturn(false);
1368 
1369         triggerDockIntent();
1370         verifyAndSendResultBroadcast();
1371         verify(mInjector).startDreamWhenDockedIfAppropriate(mContext);
1372     }
1373 
1374     @Test
dreamWhenDocked_ambientModeSuppressed_suppressionEnabled()1375     public void dreamWhenDocked_ambientModeSuppressed_suppressionEnabled() {
1376         mUiManagerService.setStartDreamImmediatelyOnDock(true);
1377         mUiManagerService.setDreamsDisabledByAmbientModeSuppression(true);
1378 
1379         when(mLocalPowerManager.isAmbientDisplaySuppressed()).thenReturn(true);
1380         triggerDockIntent();
1381         verifyAndSendResultBroadcast();
1382         verify(mInjector, never()).startDreamWhenDockedIfAppropriate(mContext);
1383     }
1384 
1385     @Test
dreamWhenDocked_ambientModeSuppressed_suppressionDisabled()1386     public void dreamWhenDocked_ambientModeSuppressed_suppressionDisabled() {
1387         mUiManagerService.setStartDreamImmediatelyOnDock(true);
1388         mUiManagerService.setDreamsDisabledByAmbientModeSuppression(false);
1389 
1390         when(mLocalPowerManager.isAmbientDisplaySuppressed()).thenReturn(true);
1391         triggerDockIntent();
1392         verifyAndSendResultBroadcast();
1393         verify(mInjector).startDreamWhenDockedIfAppropriate(mContext);
1394     }
1395 
1396     @Test
dreamWhenDocked_ambientModeNotSuppressed_suppressionEnabled()1397     public void dreamWhenDocked_ambientModeNotSuppressed_suppressionEnabled() {
1398         mUiManagerService.setStartDreamImmediatelyOnDock(true);
1399         mUiManagerService.setDreamsDisabledByAmbientModeSuppression(true);
1400 
1401         when(mLocalPowerManager.isAmbientDisplaySuppressed()).thenReturn(false);
1402         triggerDockIntent();
1403         verifyAndSendResultBroadcast();
1404         verify(mInjector).startDreamWhenDockedIfAppropriate(mContext);
1405     }
1406 
triggerDockIntent()1407     private void triggerDockIntent() {
1408         final Intent dockedIntent =
1409                 new Intent(Intent.ACTION_DOCK_EVENT)
1410                         .putExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_DESK);
1411         mDockStateChangedCallback.onReceive(mContext, dockedIntent);
1412     }
1413 
verifyAndSendResultBroadcast()1414     private void verifyAndSendResultBroadcast() {
1415         verify(mContext).sendOrderedBroadcastAsUser(
1416                 mOrderedBroadcastIntent.capture(),
1417                 any(UserHandle.class),
1418                 nullable(String.class),
1419                 mOrderedBroadcastReceiver.capture(),
1420                 nullable(Handler.class),
1421                 anyInt(),
1422                 nullable(String.class),
1423                 nullable(Bundle.class));
1424 
1425         mOrderedBroadcastReceiver.getValue().setPendingResult(
1426                 new BroadcastReceiver.PendingResult(
1427                         Activity.RESULT_OK,
1428                         /* resultData= */ "",
1429                         /* resultExtras= */ null,
1430                         /* type= */ 0,
1431                         /* ordered= */ true,
1432                         /* sticky= */ false,
1433                         /* token= */ null,
1434                         /* userId= */ 0,
1435                         /* flags= */ 0));
1436         mOrderedBroadcastReceiver.getValue().onReceive(
1437                 mContext,
1438                 mOrderedBroadcastIntent.getValue());
1439     }
1440 
requestAllPossibleProjectionTypes()1441     private void requestAllPossibleProjectionTypes() throws RemoteException {
1442         for (int i = 0; i < Integer.SIZE; ++i) {
1443             mService.requestProjection(mBinder, 1 << i, PACKAGE_NAME);
1444         }
1445     }
1446 
1447     private static class TestInjector extends UiModeManagerService.Injector {
1448         private static final int DEFAULT_CALLING_UID = 8675309;
1449 
1450         private final int callingUid;
1451 
TestInjector()1452         public TestInjector() {
1453           this(DEFAULT_CALLING_UID);
1454         }
1455 
TestInjector(int callingUid)1456         public TestInjector(int callingUid) {
1457             this.callingUid = callingUid;
1458         }
1459 
1460         @Override
getCallingUid()1461         public int getCallingUid() {
1462             return callingUid;
1463         }
1464 
1465         @Override
startDreamWhenDockedIfAppropriate(Context context)1466         public void startDreamWhenDockedIfAppropriate(Context context) {
1467             // do nothing
1468         }
1469     }
1470 }
1471