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