OSDN Git Service

DO NOT MERGE. Grant MMS Uri permissions as the calling UID.
[android-x86/frameworks-base.git] / services / core / java / com / android / server / UiModeManagerService.java
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 }