1 /* 2 * Copyright (C) 2008 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 android.app.Activity; 20 import android.app.ActivityManager; 21 import android.app.ActivityManagerNative; 22 import android.app.IUiModeManager; 23 import android.app.Notification; 24 import android.app.NotificationManager; 25 import android.app.PendingIntent; 26 import android.app.StatusBarManager; 27 import android.app.UiModeManager; 28 import android.content.BroadcastReceiver; 29 import android.content.Context; 30 import android.content.Intent; 31 import android.content.IntentFilter; 32 import android.content.pm.PackageManager; 33 import android.content.res.Configuration; 34 import android.os.BatteryManager; 35 import android.os.Binder; 36 import android.os.Handler; 37 import android.os.IBinder; 38 import android.os.PowerManager; 39 import android.os.RemoteException; 40 import android.os.UserHandle; 41 import android.provider.Settings; 42 import android.service.dreams.Sandman; 43 import android.util.Slog; 44 45 import java.io.FileDescriptor; 46 import java.io.PrintWriter; 47 48 import com.android.internal.R; 49 import com.android.internal.app.DisableCarModeActivity; 50 import com.android.server.twilight.TwilightListener; 51 import com.android.server.twilight.TwilightManager; 52 import com.android.server.twilight.TwilightState; 53 54 final class UiModeManagerService extends SystemService { 55 private static final String TAG = UiModeManager.class.getSimpleName(); 56 private static final boolean LOG = false; 57 58 // Enable launching of applications when entering the dock. 59 private static final boolean ENABLE_LAUNCH_CAR_DOCK_APP = true; 60 private static final boolean ENABLE_LAUNCH_DESK_DOCK_APP = true; 61 62 final Object mLock = new Object(); 63 private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; 64 65 private int mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED; 66 int mNightMode = UiModeManager.MODE_NIGHT_NO; 67 68 private boolean mCarModeEnabled = false; 69 private boolean mCharging = false; 70 private int mDefaultUiModeType; 71 private boolean mCarModeKeepsScreenOn; 72 private boolean mDeskModeKeepsScreenOn; 73 private boolean mTelevision; 74 private boolean mWatch; 75 private boolean mComputedNightMode; 76 private int mCarModeEnableFlags; 77 78 int mCurUiMode = 0; 79 private int mSetUiMode = 0; 80 private boolean mHoldingConfiguration = false; 81 82 private Configuration mConfiguration = new Configuration(); 83 boolean mSystemReady; 84 85 private final Handler mHandler = new Handler(); 86 87 private TwilightManager mTwilightManager; 88 private NotificationManager mNotificationManager; 89 private StatusBarManager mStatusBarManager; 90 91 private PowerManager.WakeLock mWakeLock; 92 93 public UiModeManagerService(Context context) { 94 super(context); 95 } 96 97 private static Intent buildHomeIntent(String category) { 98 Intent intent = new Intent(Intent.ACTION_MAIN); 99 intent.addCategory(category); 100 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 101 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); 102 return intent; 103 } 104 105 // The broadcast receiver which receives the result of the ordered broadcast sent when 106 // the dock state changes. The original ordered broadcast is sent with an initial result 107 // code of RESULT_OK. If any of the registered broadcast receivers changes this value, e.g., 108 // to RESULT_CANCELED, then the intent to start a dock app will not be sent. 109 private final BroadcastReceiver mResultReceiver = new BroadcastReceiver() { 110 @Override 111 public void onReceive(Context context, Intent intent) { 112 if (getResultCode() != Activity.RESULT_OK) { 113 if (LOG) { 114 Slog.v(TAG, "Handling broadcast result for action " + intent.getAction() 115 + ": canceled: " + getResultCode()); 116 } 117 return; 118 } 119 120 final int enableFlags = intent.getIntExtra("enableFlags", 0); 121 final int disableFlags = intent.getIntExtra("disableFlags", 0); 122 synchronized (mLock) { 123 updateAfterBroadcastLocked(intent.getAction(), enableFlags, disableFlags); 124 } 125 } 126 }; 127 128 private final BroadcastReceiver mDockModeReceiver = new BroadcastReceiver() { 129 @Override 130 public void onReceive(Context context, Intent intent) { 131 int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, 132 Intent.EXTRA_DOCK_STATE_UNDOCKED); 133 updateDockState(state); 134 } 135 }; 136 137 private final BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() { 138 @Override 139 public void onReceive(Context context, Intent intent) { 140 mCharging = (intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0); 141 synchronized (mLock) { 142 if (mSystemReady) { 143 updateLocked(0, 0); 144 } 145 } 146 } 147 }; 148 149 private final TwilightListener mTwilightListener = new TwilightListener() { 150 @Override 151 public void onTwilightStateChanged() { 152 updateTwilight(); 153 } 154 }; 155 156 @Override 157 public void onStart() { 158 final Context context = getContext(); 159 mTwilightManager = getLocalService(TwilightManager.class); 160 final PowerManager powerManager = 161 (PowerManager) context.getSystemService(Context.POWER_SERVICE); 162 mWakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG); 163 164 context.registerReceiver(mDockModeReceiver, 165 new IntentFilter(Intent.ACTION_DOCK_EVENT)); 166 context.registerReceiver(mBatteryReceiver, 167 new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); 168 169 mConfiguration.setToDefaults(); 170 171 mDefaultUiModeType = context.getResources().getInteger( 172 com.android.internal.R.integer.config_defaultUiModeType); 173 mCarModeKeepsScreenOn = (context.getResources().getInteger( 174 com.android.internal.R.integer.config_carDockKeepsScreenOn) == 1); 175 mDeskModeKeepsScreenOn = (context.getResources().getInteger( 176 com.android.internal.R.integer.config_deskDockKeepsScreenOn) == 1); 177 mTelevision = context.getPackageManager().hasSystemFeature( 178 PackageManager.FEATURE_TELEVISION) || 179 context.getPackageManager().hasSystemFeature( 180 PackageManager.FEATURE_LEANBACK); 181 mWatch = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH); 182 183 mNightMode = Settings.Secure.getInt(context.getContentResolver(), 184 Settings.Secure.UI_NIGHT_MODE, UiModeManager.MODE_NIGHT_AUTO); 185 186 mTwilightManager.registerListener(mTwilightListener, mHandler); 187 188 publishBinderService(Context.UI_MODE_SERVICE, mService); 189 } 190 191 private final IBinder mService = new IUiModeManager.Stub() { 192 @Override 193 public void enableCarMode(int flags) { 194 final long ident = Binder.clearCallingIdentity(); 195 try { 196 synchronized (mLock) { 197 setCarModeLocked(true, flags); 198 if (mSystemReady) { 199 updateLocked(flags, 0); 200 } 201 } 202 } finally { 203 Binder.restoreCallingIdentity(ident); 204 } 205 } 206 207 @Override 208 public void disableCarMode(int flags) { 209 final long ident = Binder.clearCallingIdentity(); 210 try { 211 synchronized (mLock) { 212 setCarModeLocked(false, 0); 213 if (mSystemReady) { 214 updateLocked(0, flags); 215 } 216 } 217 } finally { 218 Binder.restoreCallingIdentity(ident); 219 } 220 } 221 222 @Override 223 public int getCurrentModeType() { 224 final long ident = Binder.clearCallingIdentity(); 225 try { 226 synchronized (mLock) { 227 return mCurUiMode & Configuration.UI_MODE_TYPE_MASK; 228 } 229 } finally { 230 Binder.restoreCallingIdentity(ident); 231 } 232 } 233 234 @Override 235 public void setNightMode(int mode) { 236 switch (mode) { 237 case UiModeManager.MODE_NIGHT_NO: 238 case UiModeManager.MODE_NIGHT_YES: 239 case UiModeManager.MODE_NIGHT_AUTO: 240 break; 241 default: 242 throw new IllegalArgumentException("Unknown mode: " + mode); 243 } 244 245 final long ident = Binder.clearCallingIdentity(); 246 try { 247 synchronized (mLock) { 248 if (isDoingNightModeLocked() && mNightMode != mode) { 249 Settings.Secure.putInt(getContext().getContentResolver(), 250 Settings.Secure.UI_NIGHT_MODE, mode); 251 mNightMode = mode; 252 updateLocked(0, 0); 253 } 254 } 255 } finally { 256 Binder.restoreCallingIdentity(ident); 257 } 258 } 259 260 @Override 261 public int getNightMode() { 262 synchronized (mLock) { 263 return mNightMode; 264 } 265 } 266 267 @Override 268 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 269 if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 270 != PackageManager.PERMISSION_GRANTED) { 271 272 pw.println("Permission Denial: can't dump uimode service from from pid=" 273 + Binder.getCallingPid() 274 + ", uid=" + Binder.getCallingUid()); 275 return; 276 } 277 278 dumpImpl(pw); 279 } 280 }; 281 282 void dumpImpl(PrintWriter pw) { 283 synchronized (mLock) { 284 pw.println("Current UI Mode Service state:"); 285 pw.print(" mDockState="); pw.print(mDockState); 286 pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState); 287 pw.print(" mNightMode="); pw.print(mNightMode); 288 pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled); 289 pw.print(" mComputedNightMode="); pw.print(mComputedNightMode); 290 pw.print(" mCarModeEnableFlags="); pw.println(mCarModeEnableFlags); 291 pw.print(" mCurUiMode=0x"); pw.print(Integer.toHexString(mCurUiMode)); 292 pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode)); 293 pw.print(" mHoldingConfiguration="); pw.print(mHoldingConfiguration); 294 pw.print(" mSystemReady="); pw.println(mSystemReady); 295 pw.print(" mTwilightService.getCurrentState()="); 296 pw.println(mTwilightManager.getCurrentState()); 297 } 298 } 299 300 @Override 301 public void onBootPhase(int phase) { 302 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 303 synchronized (mLock) { 304 mSystemReady = true; 305 mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR; 306 updateComputedNightModeLocked(); 307 updateLocked(0, 0); 308 } 309 } 310 } 311 312 boolean isDoingNightModeLocked() { 313 return mCarModeEnabled || mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED; 314 } 315 316 void setCarModeLocked(boolean enabled, int flags) { 317 if (mCarModeEnabled != enabled) { 318 mCarModeEnabled = enabled; 319 } 320 mCarModeEnableFlags = flags; 321 } 322 323 private void updateDockState(int newState) { 324 synchronized (mLock) { 325 if (newState != mDockState) { 326 mDockState = newState; 327 setCarModeLocked(mDockState == Intent.EXTRA_DOCK_STATE_CAR, 0); 328 if (mSystemReady) { 329 updateLocked(UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME, 0); 330 } 331 } 332 } 333 } 334 335 private static boolean isDeskDockState(int state) { 336 switch (state) { 337 case Intent.EXTRA_DOCK_STATE_DESK: 338 case Intent.EXTRA_DOCK_STATE_LE_DESK: 339 case Intent.EXTRA_DOCK_STATE_HE_DESK: 340 return true; 341 default: 342 return false; 343 } 344 } 345 346 private void updateConfigurationLocked() { 347 int uiMode = mDefaultUiModeType; 348 if (mTelevision) { 349 uiMode = Configuration.UI_MODE_TYPE_TELEVISION; 350 } else if (mWatch) { 351 uiMode = Configuration.UI_MODE_TYPE_WATCH; 352 } else if (mCarModeEnabled) { 353 uiMode = Configuration.UI_MODE_TYPE_CAR; 354 } else if (isDeskDockState(mDockState)) { 355 uiMode = Configuration.UI_MODE_TYPE_DESK; 356 } 357 if (mCarModeEnabled) { 358 if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) { 359 updateComputedNightModeLocked(); 360 uiMode |= mComputedNightMode ? Configuration.UI_MODE_NIGHT_YES 361 : Configuration.UI_MODE_NIGHT_NO; 362 } else { 363 uiMode |= mNightMode << 4; 364 } 365 } else { 366 // Disabling the car mode clears the night mode. 367 uiMode = (uiMode & ~Configuration.UI_MODE_NIGHT_MASK) | Configuration.UI_MODE_NIGHT_NO; 368 } 369 370 if (LOG) { 371 Slog.d(TAG, 372 "updateConfigurationLocked: mDockState=" + mDockState 373 + "; mCarMode=" + mCarModeEnabled 374 + "; mNightMode=" + mNightMode 375 + "; uiMode=" + uiMode); 376 } 377 378 mCurUiMode = uiMode; 379 if (!mHoldingConfiguration) { 380 mConfiguration.uiMode = uiMode; 381 } 382 } 383 384 private void sendConfigurationLocked() { 385 if (mSetUiMode != mConfiguration.uiMode) { 386 mSetUiMode = mConfiguration.uiMode; 387 388 try { 389 ActivityManagerNative.getDefault().updateConfiguration(mConfiguration); 390 } catch (RemoteException e) { 391 Slog.w(TAG, "Failure communicating with activity manager", e); 392 } 393 } 394 } 395 396 void updateLocked(int enableFlags, int disableFlags) { 397 String action = null; 398 String oldAction = null; 399 if (mLastBroadcastState == Intent.EXTRA_DOCK_STATE_CAR) { 400 adjustStatusBarCarModeLocked(); 401 oldAction = UiModeManager.ACTION_EXIT_CAR_MODE; 402 } else if (isDeskDockState(mLastBroadcastState)) { 403 oldAction = UiModeManager.ACTION_EXIT_DESK_MODE; 404 } 405 406 if (mCarModeEnabled) { 407 if (mLastBroadcastState != Intent.EXTRA_DOCK_STATE_CAR) { 408 adjustStatusBarCarModeLocked(); 409 410 if (oldAction != null) { 411 getContext().sendBroadcastAsUser(new Intent(oldAction), UserHandle.ALL); 412 } 413 mLastBroadcastState = Intent.EXTRA_DOCK_STATE_CAR; 414 action = UiModeManager.ACTION_ENTER_CAR_MODE; 415 } 416 } else if (isDeskDockState(mDockState)) { 417 if (!isDeskDockState(mLastBroadcastState)) { 418 if (oldAction != null) { 419 getContext().sendBroadcastAsUser(new Intent(oldAction), UserHandle.ALL); 420 } 421 mLastBroadcastState = mDockState; 422 action = UiModeManager.ACTION_ENTER_DESK_MODE; 423 } 424 } else { 425 mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED; 426 action = oldAction; 427 } 428 429 if (action != null) { 430 if (LOG) { 431 Slog.v(TAG, String.format( 432 "updateLocked: preparing broadcast: action=%s enable=0x%08x disable=0x%08x", 433 action, enableFlags, disableFlags)); 434 } 435 436 // Send the ordered broadcast; the result receiver will receive after all 437 // broadcasts have been sent. If any broadcast receiver changes the result 438 // code from the initial value of RESULT_OK, then the result receiver will 439 // not launch the corresponding dock application. This gives apps a chance 440 // to override the behavior and stay in their app even when the device is 441 // placed into a dock. 442 Intent intent = new Intent(action); 443 intent.putExtra("enableFlags", enableFlags); 444 intent.putExtra("disableFlags", disableFlags); 445 getContext().sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null, 446 mResultReceiver, null, Activity.RESULT_OK, null, null); 447 448 // Attempting to make this transition a little more clean, we are going 449 // to hold off on doing a configuration change until we have finished 450 // the broadcast and started the home activity. 451 mHoldingConfiguration = true; 452 updateConfigurationLocked(); 453 } else { 454 String category = null; 455 if (mCarModeEnabled) { 456 if (ENABLE_LAUNCH_CAR_DOCK_APP 457 && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) { 458 category = Intent.CATEGORY_CAR_DOCK; 459 } 460 } else if (isDeskDockState(mDockState)) { 461 if (ENABLE_LAUNCH_DESK_DOCK_APP 462 && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) { 463 category = Intent.CATEGORY_DESK_DOCK; 464 } 465 } else { 466 if ((disableFlags & UiModeManager.DISABLE_CAR_MODE_GO_HOME) != 0) { 467 category = Intent.CATEGORY_HOME; 468 } 469 } 470 471 if (LOG) { 472 Slog.v(TAG, "updateLocked: null action, mDockState=" 473 + mDockState +", category=" + category); 474 } 475 476 sendConfigurationAndStartDreamOrDockAppLocked(category); 477 } 478 479 // keep screen on when charging and in car mode 480 boolean keepScreenOn = mCharging && 481 ((mCarModeEnabled && mCarModeKeepsScreenOn && 482 (mCarModeEnableFlags & UiModeManager.ENABLE_CAR_MODE_ALLOW_SLEEP) == 0) || 483 (mCurUiMode == Configuration.UI_MODE_TYPE_DESK && mDeskModeKeepsScreenOn)); 484 if (keepScreenOn != mWakeLock.isHeld()) { 485 if (keepScreenOn) { 486 mWakeLock.acquire(); 487 } else { 488 mWakeLock.release(); 489 } 490 } 491 } 492 493 private void updateAfterBroadcastLocked(String action, int enableFlags, int disableFlags) { 494 // Launch a dock activity 495 String category = null; 496 if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(action)) { 497 // Only launch car home when car mode is enabled and the caller 498 // has asked us to switch to it. 499 if (ENABLE_LAUNCH_CAR_DOCK_APP 500 && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) { 501 category = Intent.CATEGORY_CAR_DOCK; 502 } 503 } else if (UiModeManager.ACTION_ENTER_DESK_MODE.equals(action)) { 504 // Only launch car home when desk mode is enabled and the caller 505 // has asked us to switch to it. Currently re-using the car 506 // mode flag since we don't have a formal API for "desk mode". 507 if (ENABLE_LAUNCH_DESK_DOCK_APP 508 && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) { 509 category = Intent.CATEGORY_DESK_DOCK; 510 } 511 } else { 512 // Launch the standard home app if requested. 513 if ((disableFlags & UiModeManager.DISABLE_CAR_MODE_GO_HOME) != 0) { 514 category = Intent.CATEGORY_HOME; 515 } 516 } 517 518 if (LOG) { 519 Slog.v(TAG, String.format( 520 "Handling broadcast result for action %s: enable=0x%08x, disable=0x%08x, " 521 + "category=%s", 522 action, enableFlags, disableFlags, category)); 523 } 524 525 sendConfigurationAndStartDreamOrDockAppLocked(category); 526 } 527 528 private void sendConfigurationAndStartDreamOrDockAppLocked(String category) { 529 // Update the configuration but don't send it yet. 530 mHoldingConfiguration = false; 531 updateConfigurationLocked(); 532 533 // Start the dock app, if there is one. 534 boolean dockAppStarted = false; 535 if (category != null) { 536 // Now we are going to be careful about switching the 537 // configuration and starting the activity -- we need to 538 // do this in a specific order under control of the 539 // activity manager, to do it cleanly. So compute the 540 // new config, but don't set it yet, and let the 541 // activity manager take care of both the start and config 542 // change. 543 Intent homeIntent = buildHomeIntent(category); 544 if (Sandman.shouldStartDockApp(getContext(), homeIntent)) { 545 try { 546 int result = ActivityManagerNative.getDefault().startActivityWithConfig( 547 null, null, homeIntent, null, null, null, 0, 0, 548 mConfiguration, null, UserHandle.USER_CURRENT); 549 if (result >= ActivityManager.START_SUCCESS) { 550 dockAppStarted = true; 551 } else if (result != ActivityManager.START_INTENT_NOT_RESOLVED) { 552 Slog.e(TAG, "Could not start dock app: " + homeIntent 553 + ", startActivityWithConfig result " + result); 554 } 555 } catch (RemoteException ex) { 556 Slog.e(TAG, "Could not start dock app: " + homeIntent, ex); 557 } 558 } 559 } 560 561 // Send the new configuration. 562 sendConfigurationLocked(); 563 564 // If we did not start a dock app, then start dreaming if supported. 565 if (category != null && !dockAppStarted) { 566 Sandman.startDreamWhenDockedIfAppropriate(getContext()); 567 } 568 } 569 570 private void adjustStatusBarCarModeLocked() { 571 final Context context = getContext(); 572 if (mStatusBarManager == null) { 573 mStatusBarManager = (StatusBarManager) 574 context.getSystemService(Context.STATUS_BAR_SERVICE); 575 } 576 577 // Fear not: StatusBarManagerService manages a list of requests to disable 578 // features of the status bar; these are ORed together to form the 579 // active disabled list. So if (for example) the device is locked and 580 // the status bar should be totally disabled, the calls below will 581 // have no effect until the device is unlocked. 582 if (mStatusBarManager != null) { 583 mStatusBarManager.disable(mCarModeEnabled 584 ? StatusBarManager.DISABLE_NOTIFICATION_TICKER 585 : StatusBarManager.DISABLE_NONE); 586 } 587 588 if (mNotificationManager == null) { 589 mNotificationManager = (NotificationManager) 590 context.getSystemService(Context.NOTIFICATION_SERVICE); 591 } 592 593 if (mNotificationManager != null) { 594 if (mCarModeEnabled) { 595 Intent carModeOffIntent = new Intent(context, DisableCarModeActivity.class); 596 597 Notification n = new Notification(); 598 n.icon = R.drawable.stat_notify_car_mode; 599 n.defaults = Notification.DEFAULT_LIGHTS; 600 n.flags = Notification.FLAG_ONGOING_EVENT; 601 n.when = 0; 602 n.color = context.getResources().getColor( 603 com.android.internal.R.color.system_notification_accent_color); 604 n.setLatestEventInfo( 605 context, 606 context.getString(R.string.car_mode_disable_notification_title), 607 context.getString(R.string.car_mode_disable_notification_message), 608 PendingIntent.getActivityAsUser(context, 0, carModeOffIntent, 0, 609 null, UserHandle.CURRENT)); 610 mNotificationManager.notifyAsUser(null, 611 R.string.car_mode_disable_notification_title, n, UserHandle.ALL); 612 } else { 613 mNotificationManager.cancelAsUser(null, 614 R.string.car_mode_disable_notification_title, UserHandle.ALL); 615 } 616 } 617 } 618 619 void updateTwilight() { 620 synchronized (mLock) { 621 if (isDoingNightModeLocked() && mNightMode == UiModeManager.MODE_NIGHT_AUTO) { 622 updateComputedNightModeLocked(); 623 updateLocked(0, 0); 624 } 625 } 626 } 627 628 private void updateComputedNightModeLocked() { 629 TwilightState state = mTwilightManager.getCurrentState(); 630 if (state != null) { 631 mComputedNightMode = state.isNight(); 632 } 633 } 634 635 636 } 637