1 /* 2 * Copyright (C) 2010 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 android.app; 18 19 import android.annotation.IntDef; 20 import android.annotation.IntRange; 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.annotation.RequiresPermission; 24 import android.annotation.SystemApi; 25 import android.annotation.SystemService; 26 import android.annotation.TestApi; 27 import android.compat.annotation.UnsupportedAppUsage; 28 import android.content.Context; 29 import android.content.res.Configuration; 30 import android.os.RemoteException; 31 import android.os.ServiceManager; 32 import android.os.ServiceManager.ServiceNotFoundException; 33 34 import java.lang.annotation.Retention; 35 import java.lang.annotation.RetentionPolicy; 36 import java.time.LocalTime; 37 38 /** 39 * This class provides access to the system uimode services. These services 40 * allow applications to control UI modes of the device. 41 * It provides functionality to disable the car mode and it gives access to the 42 * night mode settings. 43 * 44 * <p>These facilities are built on top of the underlying 45 * {@link android.content.Intent#ACTION_DOCK_EVENT} broadcasts that are sent when the user 46 * physical places the device into and out of a dock. When that happens, 47 * the UiModeManager switches the system {@link android.content.res.Configuration} 48 * to the appropriate UI mode, sends broadcasts about the mode switch, and 49 * starts the corresponding mode activity if appropriate. See the 50 * broadcasts {@link #ACTION_ENTER_CAR_MODE} and 51 * {@link #ACTION_ENTER_DESK_MODE} for more information. 52 * 53 * <p>In addition, the user may manually switch the system to car mode without 54 * physically being in a dock. While in car mode -- whether by manual action 55 * from the user or being physically placed in a dock -- a notification is 56 * displayed allowing the user to exit dock mode. Thus the dock mode 57 * represented here may be different than the current state of the underlying 58 * dock event broadcast. 59 */ 60 @SystemService(Context.UI_MODE_SERVICE) 61 public class UiModeManager { 62 private static final String TAG = "UiModeManager"; 63 64 /** 65 * Broadcast sent when the device's UI has switched to car mode, either 66 * by being placed in a car dock or explicit action of the user. After 67 * sending the broadcast, the system will start the intent 68 * {@link android.content.Intent#ACTION_MAIN} with category 69 * {@link android.content.Intent#CATEGORY_CAR_DOCK} 70 * to display the car UI, which typically what an application would 71 * implement to provide their own interface. However, applications can 72 * also monitor this Intent in order to be informed of mode changes or 73 * prevent the normal car UI from being displayed by setting the result 74 * of the broadcast to {@link Activity#RESULT_CANCELED}. 75 * <p> 76 * This intent is broadcast when {@link #getCurrentModeType()} transitions to 77 * {@link Configuration#UI_MODE_TYPE_CAR} from some other ui mode. 78 */ 79 public static String ACTION_ENTER_CAR_MODE = "android.app.action.ENTER_CAR_MODE"; 80 81 /** 82 * Broadcast sent when an app has entered car mode using either {@link #enableCarMode(int)} or 83 * {@link #enableCarMode(int, int)}. 84 * <p> 85 * Unlike {@link #ACTION_ENTER_CAR_MODE}, which is only sent when the global car mode state 86 * (i.e. {@link #getCurrentModeType()}) transitions to {@link Configuration#UI_MODE_TYPE_CAR}, 87 * this intent is sent any time an app declares it has entered car mode. Thus, this intent is 88 * intended for use by a component which needs to know not only when the global car mode state 89 * changed, but also when the highest priority app declaring car mode has changed. 90 * <p> 91 * This broadcast includes the package name of the app which requested to enter car mode in 92 * {@link #EXTRA_CALLING_PACKAGE}. The priority the app entered car mode at is specified in 93 * {@link #EXTRA_PRIORITY}. 94 * <p> 95 * This is primarily intended to be received by other components of the Android OS. 96 * <p> 97 * Receiver requires permission: {@link android.Manifest.permission.HANDLE_CAR_MODE_CHANGES} 98 * @hide 99 */ 100 @SystemApi 101 public static final String ACTION_ENTER_CAR_MODE_PRIORITIZED = 102 "android.app.action.ENTER_CAR_MODE_PRIORITIZED"; 103 104 /** 105 * Broadcast sent when the device's UI has switch away from car mode back 106 * to normal mode. Typically used by a car mode app, to dismiss itself 107 * when the user exits car mode. 108 * <p> 109 * This intent is broadcast when {@link #getCurrentModeType()} transitions from 110 * {@link Configuration#UI_MODE_TYPE_CAR} to some other ui mode. 111 */ 112 public static String ACTION_EXIT_CAR_MODE = "android.app.action.EXIT_CAR_MODE"; 113 114 /** 115 * Broadcast sent when an app has exited car mode using {@link #disableCarMode(int)}. 116 * <p> 117 * Unlike {@link #ACTION_EXIT_CAR_MODE}, which is only sent when the global car mode state 118 * (i.e. {@link #getCurrentModeType()}) transitions to a non-car mode state such as 119 * {@link Configuration#UI_MODE_TYPE_NORMAL}, this intent is sent any time an app declares it 120 * has exited car mode. Thus, this intent is intended for use by a component which needs to 121 * know not only when the global car mode state changed, but also when the highest priority app 122 * declaring car mode has changed. 123 * <p> 124 * This broadcast includes the package name of the app which requested to exit car mode in 125 * {@link #EXTRA_CALLING_PACKAGE}. The priority the app originally entered car mode at is 126 * specified in {@link #EXTRA_PRIORITY}. 127 * <p> 128 * If {@link #DISABLE_CAR_MODE_ALL_PRIORITIES} is used when disabling car mode (i.e. this is 129 * initiated by the user via the persistent car mode notification), this broadcast is sent once 130 * for each priority level for which car mode is being disabled. 131 * <p> 132 * This is primarily intended to be received by other components of the Android OS. 133 * <p> 134 * Receiver requires permission: {@link android.Manifest.permission.HANDLE_CAR_MODE_CHANGES} 135 * @hide 136 */ 137 @SystemApi 138 public static final String ACTION_EXIT_CAR_MODE_PRIORITIZED = 139 "android.app.action.EXIT_CAR_MODE_PRIORITIZED"; 140 141 /** 142 * Broadcast sent when the device's UI has switched to desk mode, 143 * by being placed in a desk dock. After 144 * sending the broadcast, the system will start the intent 145 * {@link android.content.Intent#ACTION_MAIN} with category 146 * {@link android.content.Intent#CATEGORY_DESK_DOCK} 147 * to display the desk UI, which typically what an application would 148 * implement to provide their own interface. However, applications can 149 * also monitor this Intent in order to be informed of mode changes or 150 * prevent the normal desk UI from being displayed by setting the result 151 * of the broadcast to {@link Activity#RESULT_CANCELED}. 152 */ 153 public static String ACTION_ENTER_DESK_MODE = "android.app.action.ENTER_DESK_MODE"; 154 155 /** 156 * Broadcast sent when the device's UI has switched away from desk mode back 157 * to normal mode. Typically used by a desk mode app, to dismiss itself 158 * when the user exits desk mode. 159 */ 160 public static String ACTION_EXIT_DESK_MODE = "android.app.action.EXIT_DESK_MODE"; 161 162 /** 163 * String extra used with {@link #ACTION_ENTER_CAR_MODE_PRIORITIZED} and 164 * {@link #ACTION_EXIT_CAR_MODE_PRIORITIZED} to indicate the package name of the app which 165 * requested to enter or exit car mode. 166 * @hide 167 */ 168 @SystemApi 169 public static final String EXTRA_CALLING_PACKAGE = "android.app.extra.CALLING_PACKAGE"; 170 171 /** 172 * Integer extra used with {@link #ACTION_ENTER_CAR_MODE_PRIORITIZED} and 173 * {@link #ACTION_EXIT_CAR_MODE_PRIORITIZED} to indicate the priority level at which car mode 174 * is being disabled. 175 * @hide 176 */ 177 @SystemApi 178 public static final String EXTRA_PRIORITY = "android.app.extra.PRIORITY"; 179 180 /** @hide */ 181 @IntDef(prefix = { "MODE_" }, value = { 182 MODE_NIGHT_AUTO, 183 MODE_NIGHT_CUSTOM, 184 MODE_NIGHT_NO, 185 MODE_NIGHT_YES 186 }) 187 @Retention(RetentionPolicy.SOURCE) 188 public @interface NightMode {} 189 190 /** 191 * Constant for {@link #setNightMode(int)} and {@link #getNightMode()}: 192 * automatically switch night mode on and off based on the time. 193 */ 194 public static final int MODE_NIGHT_AUTO = 0; 195 196 /** 197 * Constant for {@link #setNightMode(int)} and {@link #getNightMode()}: 198 * automatically switch night mode on and off based on the time. 199 */ 200 public static final int MODE_NIGHT_CUSTOM = 3; 201 202 /** 203 * Constant for {@link #setNightMode(int)} and {@link #getNightMode()}: 204 * never run in night mode. 205 */ 206 public static final int MODE_NIGHT_NO = 1; 207 208 /** 209 * Constant for {@link #setNightMode(int)} and {@link #getNightMode()}: 210 * always run in night mode. 211 */ 212 public static final int MODE_NIGHT_YES = 2; 213 214 private IUiModeManager mService; 215 216 /** 217 * Context required for getting the opPackageName of API caller; maybe be {@code null} if the 218 * old constructor marked with UnSupportedAppUsage is used. 219 */ 220 private @Nullable Context mContext; 221 222 @UnsupportedAppUsage UiModeManager()223 /*package*/ UiModeManager() throws ServiceNotFoundException { 224 this(null /* context */); 225 } 226 UiModeManager(Context context)227 /*package*/ UiModeManager(Context context) throws ServiceNotFoundException { 228 mService = IUiModeManager.Stub.asInterface( 229 ServiceManager.getServiceOrThrow(Context.UI_MODE_SERVICE)); 230 mContext = context; 231 } 232 233 /** 234 * Flag for use with {@link #enableCarMode(int)}: go to the car 235 * home activity as part of the enable. Enabling this way ensures 236 * a clean transition between the current activity (in non-car-mode) and 237 * the car home activity that will serve as home while in car mode. This 238 * will switch to the car home activity even if we are already in car mode. 239 */ 240 public static final int ENABLE_CAR_MODE_GO_CAR_HOME = 0x0001; 241 242 /** 243 * Flag for use with {@link #enableCarMode(int)}: allow sleep mode while in car mode. 244 * By default, when this flag is not set, the system may hold a full wake lock to keep the 245 * screen turned on and prevent the system from entering sleep mode while in car mode. 246 * Setting this flag disables such behavior and the system may enter sleep mode 247 * if there is no other user activity and no other wake lock held. 248 * Setting this flag can be relevant for a car dock application that does not require the 249 * screen kept on. 250 */ 251 public static final int ENABLE_CAR_MODE_ALLOW_SLEEP = 0x0002; 252 253 /** @hide */ 254 @IntDef(prefix = { "ENABLE_CAR_MODE_" }, value = { 255 ENABLE_CAR_MODE_GO_CAR_HOME, 256 ENABLE_CAR_MODE_ALLOW_SLEEP 257 }) 258 @Retention(RetentionPolicy.SOURCE) 259 public @interface EnableCarMode {} 260 261 /** 262 * Force device into car mode, like it had been placed in the car dock. 263 * This will cause the device to switch to the car home UI as part of 264 * the mode switch. 265 * @param flags Must be 0. 266 */ enableCarMode(int flags)267 public void enableCarMode(int flags) { 268 enableCarMode(DEFAULT_PRIORITY, flags); 269 } 270 271 /** 272 * Force device into car mode, like it had been placed in the car dock. This will cause the 273 * device to switch to the car home UI as part of the mode switch. 274 * <p> 275 * An app may request to enter car mode when the system is already in car mode. The app may 276 * specify a "priority" when entering car mode. The device will remain in car mode 277 * (i.e. {@link #getCurrentModeType()} is {@link Configuration#UI_MODE_TYPE_CAR}) as long as 278 * there is a priority level at which car mode have been enabled. 279 * <p> 280 * Specifying a priority level when entering car mode is important in cases where multiple apps 281 * on a device implement a car-mode {@link android.telecom.InCallService} (see 282 * {@link android.telecom.TelecomManager#METADATA_IN_CALL_SERVICE_CAR_MODE_UI}). The 283 * {@link android.telecom.InCallService} associated with the highest priority app which entered 284 * car mode will be bound to by Telecom and provided with information about ongoing calls on 285 * the device. 286 * <p> 287 * System apps holding the required permission can enable car mode when the app determines the 288 * correct conditions exist for that app to be in car mode. The device maker should ensure that 289 * where multiple apps exist on the device which can potentially enter car mode, appropriate 290 * priorities are used to ensure that calls delivered by the 291 * {@link android.telecom.InCallService} API are sent to the highest priority app given the 292 * desired behavior of the car mode experience on the device. 293 * <p> 294 * If app A and app B both meet their own criteria to enable car mode, and it is desired that 295 * app B should be the one which should receive call information in that scenario, the priority 296 * for app B should be higher than the one for app A. The higher priority of app B compared to 297 * A means it will be bound to during calls and app A will not. When app B no longer meets its 298 * criteria for providing a car mode experience it uses {@link #disableCarMode(int)} to disable 299 * car mode at its priority level. The system will then unbind from app B and bind to app A as 300 * it has the next highest priority. 301 * <p> 302 * When an app enables car mode at a certain priority, it can disable car mode at the specified 303 * priority level using {@link #disableCarMode(int)}. An app may only enable car mode at a 304 * single priority. 305 * <p> 306 * Public apps are assumed to enter/exit car mode at the lowest priority, 307 * {@link #DEFAULT_PRIORITY}. 308 * 309 * @param priority The declared priority for the caller, where {@link #DEFAULT_PRIORITY} (0) is 310 * the lowest priority and higher numbers represent a higher priority. 311 * The priorities apps declare when entering car mode is determined by the 312 * device manufacturer based on the desired car mode experience. 313 * @param flags Car mode flags. 314 * @hide 315 */ 316 @SystemApi 317 @TestApi 318 @RequiresPermission(android.Manifest.permission.ENTER_CAR_MODE_PRIORITIZED) enableCarMode(@ntRangefrom = 0) int priority, @EnableCarMode int flags)319 public void enableCarMode(@IntRange(from = 0) int priority, @EnableCarMode int flags) { 320 if (mService != null) { 321 try { 322 mService.enableCarMode(flags, priority, 323 mContext == null ? null : mContext.getOpPackageName()); 324 } catch (RemoteException e) { 325 throw e.rethrowFromSystemServer(); 326 } 327 } 328 } 329 330 /** 331 * Flag for use with {@link #disableCarMode(int)}: go to the normal 332 * home activity as part of the disable. Disabling this way ensures 333 * a clean transition between the current activity (in car mode) and 334 * the original home activity (which was typically last running without 335 * being in car mode). 336 */ 337 public static final int DISABLE_CAR_MODE_GO_HOME = 0x0001; 338 339 /** 340 * Flag for use with {@link #disableCarMode(int)}: Disables car mode at ALL priority levels. 341 * Primarily intended for use from {@link com.android.internal.app.DisableCarModeActivity} to 342 * provide the user with a means to exit car mode at all priority levels. 343 * @hide 344 */ 345 public static final int DISABLE_CAR_MODE_ALL_PRIORITIES = 0x0002; 346 347 /** @hide */ 348 @IntDef(prefix = { "DISABLE_CAR_MODE_" }, value = { 349 DISABLE_CAR_MODE_GO_HOME 350 }) 351 @Retention(RetentionPolicy.SOURCE) 352 public @interface DisableCarMode {} 353 354 /** 355 * The default priority used for entering car mode. 356 * <p> 357 * Callers of the {@link #enableCarMode(int)} priority will be assigned the default priority. 358 * This is considered the lowest possible priority for enabling car mode. 359 * <p> 360 * System apps can specify a priority other than the default priority when using 361 * {@link #enableCarMode(int, int)} to enable car mode. 362 * @hide 363 */ 364 @SystemApi 365 public static final int DEFAULT_PRIORITY = 0; 366 367 /** 368 * Turn off special mode if currently in car mode. 369 * @param flags One of the disable car mode flags. 370 */ disableCarMode(@isableCarMode int flags)371 public void disableCarMode(@DisableCarMode int flags) { 372 if (mService != null) { 373 try { 374 mService.disableCarModeByCallingPackage(flags, 375 mContext == null ? null : mContext.getOpPackageName()); 376 } catch (RemoteException e) { 377 throw e.rethrowFromSystemServer(); 378 } 379 } 380 } 381 382 /** 383 * Return the current running mode type. May be one of 384 * {@link Configuration#UI_MODE_TYPE_NORMAL Configuration.UI_MODE_TYPE_NORMAL}, 385 * {@link Configuration#UI_MODE_TYPE_DESK Configuration.UI_MODE_TYPE_DESK}, 386 * {@link Configuration#UI_MODE_TYPE_CAR Configuration.UI_MODE_TYPE_CAR}, 387 * {@link Configuration#UI_MODE_TYPE_TELEVISION Configuration.UI_MODE_TYPE_TELEVISION}, 388 * {@link Configuration#UI_MODE_TYPE_APPLIANCE Configuration.UI_MODE_TYPE_APPLIANCE}, 389 * {@link Configuration#UI_MODE_TYPE_WATCH Configuration.UI_MODE_TYPE_WATCH}, or 390 * {@link Configuration#UI_MODE_TYPE_VR_HEADSET Configuration.UI_MODE_TYPE_VR_HEADSET}. 391 */ getCurrentModeType()392 public int getCurrentModeType() { 393 if (mService != null) { 394 try { 395 return mService.getCurrentModeType(); 396 } catch (RemoteException e) { 397 throw e.rethrowFromSystemServer(); 398 } 399 } 400 return Configuration.UI_MODE_TYPE_NORMAL; 401 } 402 403 /** 404 * Sets the system-wide night mode. 405 * <p> 406 * The mode can be one of: 407 * <ul> 408 * <li><em>{@link #MODE_NIGHT_NO}<em> sets the device into 409 * {@code notnight} mode</li> 410 * <li><em>{@link #MODE_NIGHT_YES}</em> sets the device into 411 * {@code night} mode</li> 412 * <li><em>{@link #MODE_NIGHT_CUSTOM}</em> automatically switches between 413 * {@code night} and {@code notnight} based on the custom time set (or default)</li> 414 * <li><em>{@link #MODE_NIGHT_AUTO}</em> automatically switches between 415 * {@code night} and {@code notnight} based on the device's current 416 * location and certain other sensors</li> 417 * </ul> 418 * <p> 419 * <strong>Note:</strong> On API 22 and below, changes to the night mode 420 * are only effective when the {@link Configuration#UI_MODE_TYPE_CAR car} 421 * or {@link Configuration#UI_MODE_TYPE_DESK desk} mode is enabled on a 422 * device. On API 23 through API 28, changes to night mode are always effective. 423 * <p> 424 * Starting in API 29, when the device is in car mode and this method is called, night mode 425 * will change, but the new setting is not persisted and the previously persisted setting 426 * will be restored when the device exits car mode. 427 * <p> 428 * Changes to night mode take effect globally and will result in a configuration change 429 * (and potentially an Activity lifecycle event) being applied to all running apps. 430 * Developers interested in an app-local implementation of night mode should consider using 431 * {@link android.support.v7.app.AppCompatDelegate#setDefaultNightMode(int)} to manage the 432 * -night qualifier locally. 433 * 434 * @param mode the night mode to set 435 * @see #getNightMode() 436 */ setNightMode(@ightMode int mode)437 public void setNightMode(@NightMode int mode) { 438 if (mService != null) { 439 try { 440 mService.setNightMode(mode); 441 } catch (RemoteException e) { 442 throw e.rethrowFromSystemServer(); 443 } 444 } 445 } 446 447 /** 448 * Returns the currently configured night mode. 449 * <p> 450 * May be one of: 451 * <ul> 452 * <li>{@link #MODE_NIGHT_NO}</li> 453 * <li>{@link #MODE_NIGHT_YES}</li> 454 * <li>{@link #MODE_NIGHT_AUTO}</li> 455 * <li>{@link #MODE_NIGHT_CUSTOM}</li> 456 * <li>{@code -1} on error</li> 457 * </ul> 458 * 459 * @return the current night mode, or {@code -1} on error 460 * @see #setNightMode(int) 461 */ getNightMode()462 public @NightMode int getNightMode() { 463 if (mService != null) { 464 try { 465 return mService.getNightMode(); 466 } catch (RemoteException e) { 467 throw e.rethrowFromSystemServer(); 468 } 469 } 470 return -1; 471 } 472 473 /** 474 * @return If UI mode is locked or not. When UI mode is locked, calls to change UI mode 475 * like {@link #enableCarMode(int)} will silently fail. 476 * @hide 477 */ 478 @TestApi isUiModeLocked()479 public boolean isUiModeLocked() { 480 if (mService != null) { 481 try { 482 return mService.isUiModeLocked(); 483 } catch (RemoteException e) { 484 throw e.rethrowFromSystemServer(); 485 } 486 } 487 return true; 488 } 489 490 /** 491 * Returns whether night mode is locked or not. 492 * <p> 493 * When night mode is locked, only privileged system components may change 494 * night mode and calls from non-privileged applications to change night 495 * mode will fail silently. 496 * 497 * @return {@code true} if night mode is locked or {@code false} otherwise 498 * @hide 499 */ 500 @TestApi isNightModeLocked()501 public boolean isNightModeLocked() { 502 if (mService != null) { 503 try { 504 return mService.isNightModeLocked(); 505 } catch (RemoteException e) { 506 throw e.rethrowFromSystemServer(); 507 } 508 } 509 return true; 510 } 511 512 /** 513 * @hide 514 */ setNightModeActivated(boolean active)515 public boolean setNightModeActivated(boolean active) { 516 if (mService != null) { 517 try { 518 return mService.setNightModeActivated(active); 519 } catch (RemoteException e) { 520 throw e.rethrowFromSystemServer(); 521 } 522 } 523 return false; 524 } 525 526 /** 527 * Returns the time of the day Dark theme activates 528 * <p> 529 * When night mode is {@link #MODE_NIGHT_CUSTOM}, the system uses 530 * this time set to activate it automatically. 531 */ 532 @NonNull getCustomNightModeStart()533 public LocalTime getCustomNightModeStart() { 534 if (mService != null) { 535 try { 536 return LocalTime.ofNanoOfDay(mService.getCustomNightModeStart() * 1000); 537 } catch (RemoteException e) { 538 throw e.rethrowFromSystemServer(); 539 } 540 } 541 return LocalTime.MIDNIGHT; 542 } 543 544 /** 545 * Sets the time of the day Dark theme activates 546 * <p> 547 * When night mode is {@link #MODE_NIGHT_CUSTOM}, the system uses 548 * this time set to activate it automatically 549 * @param time The time of the day Dark theme should activate 550 */ setCustomNightModeStart(@onNull LocalTime time)551 public void setCustomNightModeStart(@NonNull LocalTime time) { 552 if (mService != null) { 553 try { 554 mService.setCustomNightModeStart(time.toNanoOfDay() / 1000); 555 } catch (RemoteException e) { 556 throw e.rethrowFromSystemServer(); 557 } 558 } 559 } 560 561 /** 562 * Returns the time of the day Dark theme deactivates 563 * <p> 564 * When night mode is {@link #MODE_NIGHT_CUSTOM}, the system uses 565 * this time set to deactivate it automatically. 566 */ 567 @NonNull getCustomNightModeEnd()568 public LocalTime getCustomNightModeEnd() { 569 if (mService != null) { 570 try { 571 return LocalTime.ofNanoOfDay(mService.getCustomNightModeEnd() * 1000); 572 } catch (RemoteException e) { 573 throw e.rethrowFromSystemServer(); 574 } 575 } 576 return LocalTime.MIDNIGHT; 577 } 578 579 /** 580 * Sets the time of the day Dark theme deactivates 581 * <p> 582 * When night mode is {@link #MODE_NIGHT_CUSTOM}, the system uses 583 * this time set to deactivate it automatically. 584 * @param time The time of the day Dark theme should deactivate 585 */ setCustomNightModeEnd(@onNull LocalTime time)586 public void setCustomNightModeEnd(@NonNull LocalTime time) { 587 if (mService != null) { 588 try { 589 mService.setCustomNightModeEnd(time.toNanoOfDay() / 1000); 590 } catch (RemoteException e) { 591 throw e.rethrowFromSystemServer(); 592 } 593 } 594 } 595 596 } 597