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
17package com.android.server;
18
19import android.app.Activity;
20import android.app.ActivityManager;
21import android.app.ActivityManagerNative;
22import android.app.IUiModeManager;
23import android.app.Notification;
24import android.app.NotificationManager;
25import android.app.PendingIntent;
26import android.app.StatusBarManager;
27import android.app.UiModeManager;
28import android.content.BroadcastReceiver;
29import android.content.Context;
30import android.content.Intent;
31import android.content.IntentFilter;
32import android.content.pm.PackageManager;
33import android.content.res.Configuration;
34import android.os.BatteryManager;
35import android.os.Binder;
36import android.os.Handler;
37import android.os.IBinder;
38import android.os.PowerManager;
39import android.os.RemoteException;
40import android.os.UserHandle;
41import android.provider.Settings;
42import android.service.dreams.Sandman;
43import android.util.Slog;
44
45import java.io.FileDescriptor;
46import java.io.PrintWriter;
47
48import com.android.internal.R;
49import com.android.internal.app.DisableCarModeActivity;
50import com.android.server.twilight.TwilightListener;
51import com.android.server.twilight.TwilightManager;
52import com.android.server.twilight.TwilightState;
53
54final 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