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