blob: e9e31633f59c86b43b38fa1cb99de942e7f2e30f [file] [log] [blame]
Dianne Hackborn7299c412010-03-04 18:41:49 -08001/*
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;
Jeff Brown62c82e42012-09-26 01:30:41 -070020import android.app.ActivityManager;
Dianne Hackborn7299c412010-03-04 18:41:49 -080021import android.app.ActivityManagerNative;
Dianne Hackborn7299c412010-03-04 18:41:49 -080022import android.app.IUiModeManager;
23import android.app.Notification;
24import android.app.NotificationManager;
25import android.app.PendingIntent;
26import android.app.StatusBarManager;
27import android.app.UiModeManager;
Dianne Hackborn7299c412010-03-04 18:41:49 -080028import 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;
Mike Lockwoode29db6a2010-03-05 13:45:51 -050034import android.os.BatteryManager;
Dianne Hackborn7299c412010-03-04 18:41:49 -080035import android.os.Binder;
Dianne Hackborn7299c412010-03-04 18:41:49 -080036import android.os.Handler;
Mike Lockwoode29db6a2010-03-05 13:45:51 -050037import android.os.PowerManager;
Dianne Hackborn7299c412010-03-04 18:41:49 -080038import android.os.RemoteException;
39import android.os.ServiceManager;
Jeff Brown9fca9e92012-10-05 14:42:56 -070040import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070041import android.os.UserHandle;
Dianne Hackborn2ccda4d2010-03-22 21:49:15 -070042import android.provider.Settings;
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -070043import android.service.dreams.DreamService;
Jeff Brown62c82e42012-09-26 01:30:41 -070044import android.service.dreams.IDreamManager;
Dianne Hackborn7299c412010-03-04 18:41:49 -080045import android.util.Slog;
46
47import java.io.FileDescriptor;
48import java.io.PrintWriter;
49
50import com.android.internal.R;
51import com.android.internal.app.DisableCarModeActivity;
Jeff Brown2416e092012-08-21 22:12:20 -070052import com.android.server.TwilightService.TwilightState;
Dianne Hackborn7299c412010-03-04 18:41:49 -080053
54class UiModeManagerService extends IUiModeManager.Stub {
55 private static final String TAG = UiModeManager.class.getSimpleName();
56 private static final boolean LOG = false;
57
Daniel Sandler11ddf532011-11-16 11:10:03 -080058 // Enable launching of applications when entering the dock.
59 private static final boolean ENABLE_LAUNCH_CAR_DOCK_APP = true;
John Spurlock960779d2012-05-29 14:37:05 -040060 private static final boolean ENABLE_LAUNCH_DESK_DOCK_APP = true;
Daniel Sandler11ddf532011-11-16 11:10:03 -080061
Jeff Brown62c82e42012-09-26 01:30:41 -070062 private static final int DEFAULT_SCREENSAVER_ENABLED = 1;
63 private static final int DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK = 1;
64
Dianne Hackborn7299c412010-03-04 18:41:49 -080065 private final Context mContext;
Jeff Brown2416e092012-08-21 22:12:20 -070066 private final TwilightService mTwilightService;
67 private final Handler mHandler = new Handler();
Dianne Hackborn7299c412010-03-04 18:41:49 -080068
69 final Object mLock = new Object();
Bernd Holzheyba9ab182010-03-12 09:30:29 +010070
Dianne Hackborn7299c412010-03-04 18:41:49 -080071 private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
72 private int mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
Bernd Holzheyba9ab182010-03-12 09:30:29 +010073
Dianne Hackborn7299c412010-03-04 18:41:49 -080074 private int mNightMode = UiModeManager.MODE_NIGHT_NO;
75 private boolean mCarModeEnabled = false;
Mike Lockwoode29db6a2010-03-05 13:45:51 -050076 private boolean mCharging = false;
Joe Onorato44fcb832011-12-14 20:59:30 -080077 private final int mDefaultUiModeType;
Mike Lockwoode29db6a2010-03-05 13:45:51 -050078 private final boolean mCarModeKeepsScreenOn;
79 private final boolean mDeskModeKeepsScreenOn;
Dianne Hackborn0cf2c8a2012-05-17 17:29:49 -070080 private final boolean mTelevision;
Dianne Hackborn7299c412010-03-04 18:41:49 -080081
82 private boolean mComputedNightMode;
83 private int mCurUiMode = 0;
Dianne Hackbornb8b11a02010-03-10 15:53:11 -080084 private int mSetUiMode = 0;
Bernd Holzheyba9ab182010-03-12 09:30:29 +010085
Dianne Hackbornb8b11a02010-03-10 15:53:11 -080086 private boolean mHoldingConfiguration = false;
Dianne Hackborn7299c412010-03-04 18:41:49 -080087 private Configuration mConfiguration = new Configuration();
Bernd Holzheyba9ab182010-03-12 09:30:29 +010088
Dianne Hackborn7299c412010-03-04 18:41:49 -080089 private boolean mSystemReady;
90
91 private NotificationManager mNotificationManager;
92
Dianne Hackborn7299c412010-03-04 18:41:49 -080093 private StatusBarManager mStatusBarManager;
Jeff Brown9fca9e92012-10-05 14:42:56 -070094
95 private final PowerManager mPowerManager;
Mike Lockwoode29db6a2010-03-05 13:45:51 -050096 private final PowerManager.WakeLock mWakeLock;
Dianne Hackborn7299c412010-03-04 18:41:49 -080097
Dianne Hackbornf5c5d222010-04-09 13:14:48 -070098 static Intent buildHomeIntent(String category) {
99 Intent intent = new Intent(Intent.ACTION_MAIN);
100 intent.addCategory(category);
101 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
102 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
103 return intent;
104 }
John Spurlock960779d2012-05-29 14:37:05 -0400105
Dianne Hackborn7299c412010-03-04 18:41:49 -0800106 // The broadcast receiver which receives the result of the ordered broadcast sent when
107 // the dock state changes. The original ordered broadcast is sent with an initial result
108 // code of RESULT_OK. If any of the registered broadcast receivers changes this value, e.g.,
109 // to RESULT_CANCELED, then the intent to start a dock app will not be sent.
110 private final BroadcastReceiver mResultReceiver = new BroadcastReceiver() {
111 @Override
112 public void onReceive(Context context, Intent intent) {
113 if (getResultCode() != Activity.RESULT_OK) {
Daniel Sandler69a1da42011-11-04 15:08:30 -0400114 if (LOG) {
John Spurlock960779d2012-05-29 14:37:05 -0400115 Slog.v(TAG, "Handling broadcast result for action " + intent.getAction()
Daniel Sandler69a1da42011-11-04 15:08:30 -0400116 + ": canceled: " + getResultCode());
117 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800118 return;
119 }
120
Jeff Brown62c82e42012-09-26 01:30:41 -0700121 final int enableFlags = intent.getIntExtra("enableFlags", 0);
122 final int disableFlags = intent.getIntExtra("disableFlags", 0);
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800123 synchronized (mLock) {
Jeff Brown62c82e42012-09-26 01:30:41 -0700124 updateAfterBroadcastLocked(intent.getAction(), enableFlags, disableFlags);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800125 }
126 }
127 };
128
Dianne Hackborn7299c412010-03-04 18:41:49 -0800129 private final BroadcastReceiver mDockModeReceiver = new BroadcastReceiver() {
130 @Override
131 public void onReceive(Context context, Intent intent) {
132 int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
133 Intent.EXTRA_DOCK_STATE_UNDOCKED);
134 updateDockState(state);
135 }
136 };
137
Mike Lockwoode29db6a2010-03-05 13:45:51 -0500138 private final BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() {
139 @Override
140 public void onReceive(Context context, Intent intent) {
141 mCharging = (intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0);
142 synchronized (mLock) {
143 if (mSystemReady) {
Dianne Hackbornf5c5d222010-04-09 13:14:48 -0700144 updateLocked(0, 0);
Mike Lockwoode29db6a2010-03-05 13:45:51 -0500145 }
146 }
147 }
148 };
149
Jeff Brown2416e092012-08-21 22:12:20 -0700150 private final TwilightService.TwilightListener mTwilightListener =
151 new TwilightService.TwilightListener() {
Dianne Hackborn57f45032010-06-17 15:49:33 -0700152 @Override
Jeff Brown2416e092012-08-21 22:12:20 -0700153 public void onTwilightStateChanged() {
154 updateTwilight();
Dianne Hackborn57f45032010-06-17 15:49:33 -0700155 }
156 };
157
Jeff Brown2416e092012-08-21 22:12:20 -0700158 public UiModeManagerService(Context context, TwilightService twilight) {
Dianne Hackborn7299c412010-03-04 18:41:49 -0800159 mContext = context;
Jeff Brown2416e092012-08-21 22:12:20 -0700160 mTwilightService = twilight;
Dianne Hackborn7299c412010-03-04 18:41:49 -0800161
162 ServiceManager.addService(Context.UI_MODE_SERVICE, this);
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100163
Dianne Hackborn7299c412010-03-04 18:41:49 -0800164 mContext.registerReceiver(mDockModeReceiver,
165 new IntentFilter(Intent.ACTION_DOCK_EVENT));
Mike Lockwoode29db6a2010-03-05 13:45:51 -0500166 mContext.registerReceiver(mBatteryReceiver,
167 new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
168
Jeff Brown9fca9e92012-10-05 14:42:56 -0700169 mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
170 mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800171
172 mConfiguration.setToDefaults();
Mike Lockwoode29db6a2010-03-05 13:45:51 -0500173
Joe Onorato44fcb832011-12-14 20:59:30 -0800174 mDefaultUiModeType = context.getResources().getInteger(
175 com.android.internal.R.integer.config_defaultUiModeType);
Mike Lockwoode29db6a2010-03-05 13:45:51 -0500176 mCarModeKeepsScreenOn = (context.getResources().getInteger(
177 com.android.internal.R.integer.config_carDockKeepsScreenOn) == 1);
178 mDeskModeKeepsScreenOn = (context.getResources().getInteger(
179 com.android.internal.R.integer.config_deskDockKeepsScreenOn) == 1);
Dianne Hackborn0cf2c8a2012-05-17 17:29:49 -0700180 mTelevision = context.getPackageManager().hasSystemFeature(
181 PackageManager.FEATURE_TELEVISION);
182
Dianne Hackborn2ccda4d2010-03-22 21:49:15 -0700183 mNightMode = Settings.Secure.getInt(mContext.getContentResolver(),
184 Settings.Secure.UI_NIGHT_MODE, UiModeManager.MODE_NIGHT_AUTO);
Jeff Brown2416e092012-08-21 22:12:20 -0700185
186 mTwilightService.registerListener(mTwilightListener, mHandler);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800187 }
188
Dianne Hackbornd49258f2010-03-26 00:44:29 -0700189 public void disableCarMode(int flags) {
Dianne Hackborn7299c412010-03-04 18:41:49 -0800190 synchronized (mLock) {
191 setCarModeLocked(false);
Mike Lockwood924e1642010-03-05 11:56:53 -0500192 if (mSystemReady) {
Dianne Hackbornf5c5d222010-04-09 13:14:48 -0700193 updateLocked(0, flags);
Mike Lockwood924e1642010-03-05 11:56:53 -0500194 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800195 }
196 }
197
Dianne Hackbornf5c5d222010-04-09 13:14:48 -0700198 public void enableCarMode(int flags) {
Dianne Hackborn7299c412010-03-04 18:41:49 -0800199 synchronized (mLock) {
200 setCarModeLocked(true);
Mike Lockwood924e1642010-03-05 11:56:53 -0500201 if (mSystemReady) {
Dianne Hackbornf5c5d222010-04-09 13:14:48 -0700202 updateLocked(flags, 0);
Mike Lockwood924e1642010-03-05 11:56:53 -0500203 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800204 }
205 }
206
207 public int getCurrentModeType() {
208 synchronized (mLock) {
209 return mCurUiMode & Configuration.UI_MODE_TYPE_MASK;
210 }
211 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100212
Dianne Hackborn7299c412010-03-04 18:41:49 -0800213 public void setNightMode(int mode) throws RemoteException {
214 synchronized (mLock) {
215 switch (mode) {
216 case UiModeManager.MODE_NIGHT_NO:
217 case UiModeManager.MODE_NIGHT_YES:
218 case UiModeManager.MODE_NIGHT_AUTO:
219 break;
220 default:
221 throw new IllegalArgumentException("Unknown mode: " + mode);
222 }
223 if (!isDoingNightMode()) {
224 return;
225 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100226
Dianne Hackborn7299c412010-03-04 18:41:49 -0800227 if (mNightMode != mode) {
Dianne Hackborn2ccda4d2010-03-22 21:49:15 -0700228 long ident = Binder.clearCallingIdentity();
229 Settings.Secure.putInt(mContext.getContentResolver(),
230 Settings.Secure.UI_NIGHT_MODE, mode);
231 Binder.restoreCallingIdentity(ident);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800232 mNightMode = mode;
Dianne Hackbornf5c5d222010-04-09 13:14:48 -0700233 updateLocked(0, 0);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800234 }
235 }
236 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100237
Dianne Hackborn7299c412010-03-04 18:41:49 -0800238 public int getNightMode() throws RemoteException {
239 return mNightMode;
240 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100241
Dianne Hackborn7299c412010-03-04 18:41:49 -0800242 void systemReady() {
243 synchronized (mLock) {
244 mSystemReady = true;
245 mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR;
Jeff Brown2416e092012-08-21 22:12:20 -0700246 updateComputedNightModeLocked();
Dianne Hackbornf5c5d222010-04-09 13:14:48 -0700247 updateLocked(0, 0);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800248 }
249 }
250
251 boolean isDoingNightMode() {
252 return mCarModeEnabled || mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED;
253 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100254
Dianne Hackborn7299c412010-03-04 18:41:49 -0800255 void setCarModeLocked(boolean enabled) {
256 if (mCarModeEnabled != enabled) {
257 mCarModeEnabled = enabled;
Dianne Hackborn7299c412010-03-04 18:41:49 -0800258 }
259 }
260
261 void updateDockState(int newState) {
262 synchronized (mLock) {
263 if (newState != mDockState) {
264 mDockState = newState;
Mike Lockwood924e1642010-03-05 11:56:53 -0500265 setCarModeLocked(mDockState == Intent.EXTRA_DOCK_STATE_CAR);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800266 if (mSystemReady) {
Dianne Hackbornf5c5d222010-04-09 13:14:48 -0700267 updateLocked(UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME, 0);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800268 }
269 }
270 }
271 }
Mike Lockwoode29db6a2010-03-05 13:45:51 -0500272
Daniel Sandler69a1da42011-11-04 15:08:30 -0400273 final static boolean isDeskDockState(int state) {
274 switch (state) {
275 case Intent.EXTRA_DOCK_STATE_DESK:
276 case Intent.EXTRA_DOCK_STATE_LE_DESK:
277 case Intent.EXTRA_DOCK_STATE_HE_DESK:
278 return true;
279 default:
280 return false;
281 }
282 }
283
Jeff Brown62c82e42012-09-26 01:30:41 -0700284 final void updateConfigurationLocked() {
285 int uiMode = mTelevision ? Configuration.UI_MODE_TYPE_TELEVISION : mDefaultUiModeType;
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800286 if (mCarModeEnabled) {
287 uiMode = Configuration.UI_MODE_TYPE_CAR;
Daniel Sandler69a1da42011-11-04 15:08:30 -0400288 } else if (isDeskDockState(mDockState)) {
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800289 uiMode = Configuration.UI_MODE_TYPE_DESK;
290 }
Dianne Hackborn9c9c5322010-03-30 23:12:22 -0700291 if (mCarModeEnabled) {
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800292 if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
Jeff Brown2416e092012-08-21 22:12:20 -0700293 updateComputedNightModeLocked();
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800294 uiMode |= mComputedNightMode ? Configuration.UI_MODE_NIGHT_YES
295 : Configuration.UI_MODE_NIGHT_NO;
296 } else {
297 uiMode |= mNightMode << 4;
298 }
299 } else {
300 // Disabling the car mode clears the night mode.
Daniel Sandler8daf2a42010-04-02 10:15:09 -0400301 uiMode = (uiMode & ~Configuration.UI_MODE_NIGHT_MASK) | Configuration.UI_MODE_NIGHT_NO;
302 }
303
304 if (LOG) {
John Spurlock960779d2012-05-29 14:37:05 -0400305 Slog.d(TAG,
306 "updateConfigurationLocked: mDockState=" + mDockState
Daniel Sandler8daf2a42010-04-02 10:15:09 -0400307 + "; mCarMode=" + mCarModeEnabled
308 + "; mNightMode=" + mNightMode
309 + "; uiMode=" + uiMode);
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800310 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100311
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800312 mCurUiMode = uiMode;
Jeff Brown62c82e42012-09-26 01:30:41 -0700313 if (!mHoldingConfiguration) {
Dianne Hackborn2ccda4d2010-03-22 21:49:15 -0700314 mConfiguration.uiMode = uiMode;
Jeff Brown62c82e42012-09-26 01:30:41 -0700315 }
316 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100317
Jeff Brown62c82e42012-09-26 01:30:41 -0700318 final void sendConfigurationLocked() {
319 if (mSetUiMode != mConfiguration.uiMode) {
320 mSetUiMode = mConfiguration.uiMode;
321
322 try {
323 ActivityManagerNative.getDefault().updateConfiguration(mConfiguration);
324 } catch (RemoteException e) {
325 Slog.w(TAG, "Failure communicating with activity manager", e);
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800326 }
327 }
328 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100329
Dianne Hackbornf5c5d222010-04-09 13:14:48 -0700330 final void updateLocked(int enableFlags, int disableFlags) {
Dianne Hackborn7299c412010-03-04 18:41:49 -0800331 long ident = Binder.clearCallingIdentity();
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100332
Dianne Hackborn7299c412010-03-04 18:41:49 -0800333 try {
Dianne Hackborn7299c412010-03-04 18:41:49 -0800334 String action = null;
335 String oldAction = null;
336 if (mLastBroadcastState == Intent.EXTRA_DOCK_STATE_CAR) {
Tobias Haamel780b2602010-03-15 12:54:45 +0100337 adjustStatusBarCarModeLocked();
Dianne Hackborn7299c412010-03-04 18:41:49 -0800338 oldAction = UiModeManager.ACTION_EXIT_CAR_MODE;
Daniel Sandler69a1da42011-11-04 15:08:30 -0400339 } else if (isDeskDockState(mLastBroadcastState)) {
Dianne Hackborn7299c412010-03-04 18:41:49 -0800340 oldAction = UiModeManager.ACTION_EXIT_DESK_MODE;
341 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100342
Dianne Hackborn7299c412010-03-04 18:41:49 -0800343 if (mCarModeEnabled) {
344 if (mLastBroadcastState != Intent.EXTRA_DOCK_STATE_CAR) {
345 adjustStatusBarCarModeLocked();
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100346
Dianne Hackborn7299c412010-03-04 18:41:49 -0800347 if (oldAction != null) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700348 mContext.sendBroadcastAsUser(new Intent(oldAction), UserHandle.ALL);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800349 }
350 mLastBroadcastState = Intent.EXTRA_DOCK_STATE_CAR;
351 action = UiModeManager.ACTION_ENTER_CAR_MODE;
352 }
Daniel Sandler69a1da42011-11-04 15:08:30 -0400353 } else if (isDeskDockState(mDockState)) {
354 if (!isDeskDockState(mLastBroadcastState)) {
Dianne Hackborn7299c412010-03-04 18:41:49 -0800355 if (oldAction != null) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700356 mContext.sendBroadcastAsUser(new Intent(oldAction), UserHandle.ALL);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800357 }
Daniel Sandler69a1da42011-11-04 15:08:30 -0400358 mLastBroadcastState = mDockState;
Dianne Hackborn7299c412010-03-04 18:41:49 -0800359 action = UiModeManager.ACTION_ENTER_DESK_MODE;
360 }
361 } else {
Dianne Hackborn7299c412010-03-04 18:41:49 -0800362 mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
363 action = oldAction;
364 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100365
Dianne Hackborn7299c412010-03-04 18:41:49 -0800366 if (action != null) {
Daniel Sandler69a1da42011-11-04 15:08:30 -0400367 if (LOG) {
368 Slog.v(TAG, String.format(
369 "updateLocked: preparing broadcast: action=%s enable=0x%08x disable=0x%08x",
370 action, enableFlags, disableFlags));
371 }
372
Dianne Hackborn7299c412010-03-04 18:41:49 -0800373 // Send the ordered broadcast; the result receiver will receive after all
374 // broadcasts have been sent. If any broadcast receiver changes the result
375 // code from the initial value of RESULT_OK, then the result receiver will
376 // not launch the corresponding dock application. This gives apps a chance
377 // to override the behavior and stay in their app even when the device is
378 // placed into a dock.
Dianne Hackbornf5c5d222010-04-09 13:14:48 -0700379 Intent intent = new Intent(action);
380 intent.putExtra("enableFlags", enableFlags);
381 intent.putExtra("disableFlags", disableFlags);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700382 mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
Dianne Hackborn7299c412010-03-04 18:41:49 -0800383 mResultReceiver, null, Activity.RESULT_OK, null, null);
Jeff Brown62c82e42012-09-26 01:30:41 -0700384
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800385 // Attempting to make this transition a little more clean, we are going
386 // to hold off on doing a configuration change until we have finished
Dianne Hackbornf5c5d222010-04-09 13:14:48 -0700387 // the broadcast and started the home activity.
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800388 mHoldingConfiguration = true;
Jeff Brown62c82e42012-09-26 01:30:41 -0700389 updateConfigurationLocked();
Dianne Hackbornf5c5d222010-04-09 13:14:48 -0700390 } else {
Jeff Brown62c82e42012-09-26 01:30:41 -0700391 String category = null;
Dianne Hackbornf5c5d222010-04-09 13:14:48 -0700392 if (mCarModeEnabled) {
Daniel Sandler11ddf532011-11-16 11:10:03 -0800393 if (ENABLE_LAUNCH_CAR_DOCK_APP
Jeff Brown62c82e42012-09-26 01:30:41 -0700394 && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
395 category = Intent.CATEGORY_CAR_DOCK;
Dianne Hackbornf5c5d222010-04-09 13:14:48 -0700396 }
Daniel Sandler69a1da42011-11-04 15:08:30 -0400397 } else if (isDeskDockState(mDockState)) {
Daniel Sandler11ddf532011-11-16 11:10:03 -0800398 if (ENABLE_LAUNCH_DESK_DOCK_APP
Jeff Brown62c82e42012-09-26 01:30:41 -0700399 && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
400 category = Intent.CATEGORY_DESK_DOCK;
Dianne Hackbornf5c5d222010-04-09 13:14:48 -0700401 }
402 } else {
Jeff Brown62c82e42012-09-26 01:30:41 -0700403 if ((disableFlags & UiModeManager.DISABLE_CAR_MODE_GO_HOME) != 0) {
404 category = Intent.CATEGORY_HOME;
Dianne Hackbornf5c5d222010-04-09 13:14:48 -0700405 }
406 }
Daniel Sandler69a1da42011-11-04 15:08:30 -0400407
408 if (LOG) {
409 Slog.v(TAG, "updateLocked: null action, mDockState="
Jeff Brown62c82e42012-09-26 01:30:41 -0700410 + mDockState +", category=" + category);
Daniel Sandler69a1da42011-11-04 15:08:30 -0400411 }
412
Jeff Brown62c82e42012-09-26 01:30:41 -0700413 sendConfigurationAndStartDreamOrDockAppLocked(category);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800414 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100415
Mike Lockwoode29db6a2010-03-05 13:45:51 -0500416 // keep screen on when charging and in car mode
417 boolean keepScreenOn = mCharging &&
418 ((mCarModeEnabled && mCarModeKeepsScreenOn) ||
419 (mCurUiMode == Configuration.UI_MODE_TYPE_DESK && mDeskModeKeepsScreenOn));
420 if (keepScreenOn != mWakeLock.isHeld()) {
421 if (keepScreenOn) {
422 mWakeLock.acquire();
423 } else {
424 mWakeLock.release();
425 }
426 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800427 } finally {
428 Binder.restoreCallingIdentity(ident);
429 }
430 }
431
Jeff Brown62c82e42012-09-26 01:30:41 -0700432 private void updateAfterBroadcastLocked(String action, int enableFlags, int disableFlags) {
433 // Launch a dock activity
434 String category = null;
435 if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(action)) {
436 // Only launch car home when car mode is enabled and the caller
437 // has asked us to switch to it.
438 if (ENABLE_LAUNCH_CAR_DOCK_APP
439 && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
440 category = Intent.CATEGORY_CAR_DOCK;
441 }
442 } else if (UiModeManager.ACTION_ENTER_DESK_MODE.equals(action)) {
443 // Only launch car home when desk mode is enabled and the caller
444 // has asked us to switch to it. Currently re-using the car
445 // mode flag since we don't have a formal API for "desk mode".
446 if (ENABLE_LAUNCH_DESK_DOCK_APP
447 && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
448 category = Intent.CATEGORY_DESK_DOCK;
449 }
450 } else {
451 // Launch the standard home app if requested.
452 if ((disableFlags & UiModeManager.DISABLE_CAR_MODE_GO_HOME) != 0) {
453 category = Intent.CATEGORY_HOME;
454 }
455 }
456
457 if (LOG) {
458 Slog.v(TAG, String.format(
459 "Handling broadcast result for action %s: enable=0x%08x, disable=0x%08x, "
460 + "category=%s",
461 action, enableFlags, disableFlags, category));
462 }
463
464 sendConfigurationAndStartDreamOrDockAppLocked(category);
465 }
466
467 private void sendConfigurationAndStartDreamOrDockAppLocked(String category) {
468 // Update the configuration but don't send it yet.
469 mHoldingConfiguration = false;
470 updateConfigurationLocked();
471
472 // Start the dock app, if there is one.
473 boolean dockAppStarted = false;
474 if (category != null) {
475 // Now we are going to be careful about switching the
476 // configuration and starting the activity -- we need to
477 // do this in a specific order under control of the
478 // activity manager, to do it cleanly. So compute the
479 // new config, but don't set it yet, and let the
480 // activity manager take care of both the start and config
481 // change.
482 Intent homeIntent = buildHomeIntent(category);
483 try {
484 int result = ActivityManagerNative.getDefault().startActivityWithConfig(
485 null, homeIntent, null, null, null, 0, 0,
486 mConfiguration, null, UserHandle.USER_CURRENT);
487 if (result >= ActivityManager.START_SUCCESS) {
488 dockAppStarted = true;
489 } else if (result != ActivityManager.START_INTENT_NOT_RESOLVED) {
490 Slog.e(TAG, "Could not start dock app: " + homeIntent
491 + ", startActivityWithConfig result " + result);
492 }
493 } catch (RemoteException ex) {
494 Slog.e(TAG, "Could not start dock app: " + homeIntent, ex);
495 }
496 }
497
498 // Send the new configuration.
499 sendConfigurationLocked();
500
501 // If we did not start a dock app, then start dreaming if supported.
Jeff Brownf9d40f42012-09-26 18:57:48 -0700502 if (category != null && !dockAppStarted
503 && isScreenSaverEnabled() && isScreenSaverActivatedOnDock()) {
Jeff Brown62c82e42012-09-26 01:30:41 -0700504 Slog.i(TAG, "Activating dream while docked.");
505 try {
506 IDreamManager dreamManagerService = IDreamManager.Stub.asInterface(
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700507 ServiceManager.getService(DreamService.DREAM_SERVICE));
Jeff Brown9fca9e92012-10-05 14:42:56 -0700508 if (dreamManagerService != null && !dreamManagerService.isDreaming()) {
509 // Wake up.
510 // The power manager will wake up the system when it starts receiving power
511 // but there is a race between that happening and the UI mode manager
512 // starting a dream. We want the system to already be awake
513 // by the time this happens. Otherwise the dream may not start.
514 mPowerManager.wakeUp(SystemClock.uptimeMillis());
515
516 // Dream.
517 dreamManagerService.dream();
518 }
Jeff Brown62c82e42012-09-26 01:30:41 -0700519 } catch (RemoteException ex) {
520 Slog.e(TAG, "Could not start dream when docked.", ex);
521 }
522 }
523 }
524
525 private boolean isScreenSaverEnabled() {
526 return Settings.Secure.getIntForUser(mContext.getContentResolver(),
527 Settings.Secure.SCREENSAVER_ENABLED, DEFAULT_SCREENSAVER_ENABLED,
528 UserHandle.USER_CURRENT) != 0;
529 }
530
531 private boolean isScreenSaverActivatedOnDock() {
532 return Settings.Secure.getIntForUser(mContext.getContentResolver(),
533 Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
534 DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK, UserHandle.USER_CURRENT) != 0;
535 }
536
Dianne Hackborn7299c412010-03-04 18:41:49 -0800537 private void adjustStatusBarCarModeLocked() {
538 if (mStatusBarManager == null) {
539 mStatusBarManager = (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE);
540 }
541
Joe Onorato089de882010-04-12 08:18:45 -0700542 // Fear not: StatusBarManagerService manages a list of requests to disable
Dianne Hackborn7299c412010-03-04 18:41:49 -0800543 // features of the status bar; these are ORed together to form the
544 // active disabled list. So if (for example) the device is locked and
545 // the status bar should be totally disabled, the calls below will
546 // have no effect until the device is unlocked.
547 if (mStatusBarManager != null) {
548 mStatusBarManager.disable(mCarModeEnabled
549 ? StatusBarManager.DISABLE_NOTIFICATION_TICKER
550 : StatusBarManager.DISABLE_NONE);
551 }
552
553 if (mNotificationManager == null) {
554 mNotificationManager = (NotificationManager)
555 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
556 }
557
558 if (mNotificationManager != null) {
559 if (mCarModeEnabled) {
560 Intent carModeOffIntent = new Intent(mContext, DisableCarModeActivity.class);
561
562 Notification n = new Notification();
563 n.icon = R.drawable.stat_notify_car_mode;
564 n.defaults = Notification.DEFAULT_LIGHTS;
565 n.flags = Notification.FLAG_ONGOING_EVENT;
566 n.when = 0;
567 n.setLatestEventInfo(
568 mContext,
569 mContext.getString(R.string.car_mode_disable_notification_title),
570 mContext.getString(R.string.car_mode_disable_notification_message),
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700571 PendingIntent.getActivityAsUser(mContext, 0, carModeOffIntent, 0,
572 null, UserHandle.CURRENT));
573 mNotificationManager.notifyAsUser(null,
574 R.string.car_mode_disable_notification_title, n, UserHandle.ALL);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800575 } else {
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700576 mNotificationManager.cancelAsUser(null,
577 R.string.car_mode_disable_notification_title, UserHandle.ALL);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800578 }
579 }
580 }
581
Jeff Brown2416e092012-08-21 22:12:20 -0700582 private void updateTwilight() {
583 synchronized (mLock) {
584 if (isDoingNightMode() && mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
585 updateComputedNightModeLocked();
586 updateLocked(0, 0);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800587 }
588 }
Jeff Brown2416e092012-08-21 22:12:20 -0700589 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800590
Jeff Brown2416e092012-08-21 22:12:20 -0700591 private void updateComputedNightModeLocked() {
592 TwilightState state = mTwilightService.getCurrentState();
593 if (state != null) {
594 mComputedNightMode = state.isNight();
Dianne Hackborn7299c412010-03-04 18:41:49 -0800595 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800596 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100597
Dianne Hackborn7299c412010-03-04 18:41:49 -0800598 @Override
599 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
600 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
601 != PackageManager.PERMISSION_GRANTED) {
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100602
Dianne Hackborn7299c412010-03-04 18:41:49 -0800603 pw.println("Permission Denial: can't dump uimode service from from pid="
604 + Binder.getCallingPid()
605 + ", uid=" + Binder.getCallingUid());
606 return;
607 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100608
Dianne Hackborn7299c412010-03-04 18:41:49 -0800609 synchronized (mLock) {
610 pw.println("Current UI Mode Service state:");
611 pw.print(" mDockState="); pw.print(mDockState);
612 pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState);
613 pw.print(" mNightMode="); pw.print(mNightMode);
614 pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled);
615 pw.print(" mComputedNightMode="); pw.println(mComputedNightMode);
616 pw.print(" mCurUiMode=0x"); pw.print(Integer.toHexString(mCurUiMode));
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800617 pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode));
618 pw.print(" mHoldingConfiguration="); pw.print(mHoldingConfiguration);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800619 pw.print(" mSystemReady="); pw.println(mSystemReady);
Jeff Brown2416e092012-08-21 22:12:20 -0700620 pw.print(" mTwilightService.getCurrentState()=");
621 pw.println(mTwilightService.getCurrentState());
Dianne Hackborn7299c412010-03-04 18:41:49 -0800622 }
623 }
624}