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