blob: 2d4eb79e92c00678f948e964994399db902a5eeb [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
Jeff Brown487bb6e2012-10-11 13:35:42 -070054final class UiModeManagerService extends IUiModeManager.Stub {
Dianne Hackborn7299c412010-03-04 18:41:49 -080055 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
Jeff Brown487bb6e2012-10-11 13:35:42 -0700189 @Override // Binder call
Dianne Hackbornd49258f2010-03-26 00:44:29 -0700190 public void disableCarMode(int flags) {
Jeff Brown487bb6e2012-10-11 13:35:42 -0700191 final long ident = Binder.clearCallingIdentity();
192 try {
193 synchronized (mLock) {
194 setCarModeLocked(false);
195 if (mSystemReady) {
196 updateLocked(0, flags);
197 }
Mike Lockwood924e1642010-03-05 11:56:53 -0500198 }
Jeff Brown487bb6e2012-10-11 13:35:42 -0700199 } finally {
200 Binder.restoreCallingIdentity(ident);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800201 }
202 }
203
Jeff Brown487bb6e2012-10-11 13:35:42 -0700204 @Override // Binder call
Dianne Hackbornf5c5d222010-04-09 13:14:48 -0700205 public void enableCarMode(int flags) {
Jeff Brown487bb6e2012-10-11 13:35:42 -0700206 final long ident = Binder.clearCallingIdentity();
207 try {
208 synchronized (mLock) {
209 setCarModeLocked(true);
210 if (mSystemReady) {
211 updateLocked(flags, 0);
212 }
Mike Lockwood924e1642010-03-05 11:56:53 -0500213 }
Jeff Brown487bb6e2012-10-11 13:35:42 -0700214 } finally {
215 Binder.restoreCallingIdentity(ident);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800216 }
217 }
218
Jeff Brown487bb6e2012-10-11 13:35:42 -0700219 @Override // Binder call
Dianne Hackborn7299c412010-03-04 18:41:49 -0800220 public int getCurrentModeType() {
Jeff Brown487bb6e2012-10-11 13:35:42 -0700221 final long ident = Binder.clearCallingIdentity();
222 try {
223 synchronized (mLock) {
224 return mCurUiMode & Configuration.UI_MODE_TYPE_MASK;
225 }
226 } finally {
227 Binder.restoreCallingIdentity(ident);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800228 }
229 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100230
Jeff Brown487bb6e2012-10-11 13:35:42 -0700231 @Override // Binder call
232 public void setNightMode(int mode) {
233 switch (mode) {
234 case UiModeManager.MODE_NIGHT_NO:
235 case UiModeManager.MODE_NIGHT_YES:
236 case UiModeManager.MODE_NIGHT_AUTO:
237 break;
238 default:
239 throw new IllegalArgumentException("Unknown mode: " + mode);
240 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100241
Jeff Brown487bb6e2012-10-11 13:35:42 -0700242 final long ident = Binder.clearCallingIdentity();
243 try {
244 synchronized (mLock) {
245 if (isDoingNightModeLocked() && mNightMode != mode) {
246 Settings.Secure.putInt(mContext.getContentResolver(),
247 Settings.Secure.UI_NIGHT_MODE, mode);
248 mNightMode = mode;
249 updateLocked(0, 0);
250 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800251 }
Jeff Brown487bb6e2012-10-11 13:35:42 -0700252 } finally {
253 Binder.restoreCallingIdentity(ident);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800254 }
255 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100256
Jeff Brown487bb6e2012-10-11 13:35:42 -0700257 @Override // Binder call
258 public int getNightMode() {
259 synchronized (mLock) {
260 return mNightMode;
261 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800262 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100263
Dianne Hackborn7299c412010-03-04 18:41:49 -0800264 void systemReady() {
265 synchronized (mLock) {
266 mSystemReady = true;
267 mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR;
Jeff Brown2416e092012-08-21 22:12:20 -0700268 updateComputedNightModeLocked();
Dianne Hackbornf5c5d222010-04-09 13:14:48 -0700269 updateLocked(0, 0);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800270 }
271 }
272
Jeff Brown487bb6e2012-10-11 13:35:42 -0700273 private boolean isDoingNightModeLocked() {
Dianne Hackborn7299c412010-03-04 18:41:49 -0800274 return mCarModeEnabled || mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED;
275 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100276
Jeff Brown487bb6e2012-10-11 13:35:42 -0700277 private void setCarModeLocked(boolean enabled) {
Dianne Hackborn7299c412010-03-04 18:41:49 -0800278 if (mCarModeEnabled != enabled) {
279 mCarModeEnabled = enabled;
Dianne Hackborn7299c412010-03-04 18:41:49 -0800280 }
281 }
282
Jeff Brown487bb6e2012-10-11 13:35:42 -0700283 private void updateDockState(int newState) {
Dianne Hackborn7299c412010-03-04 18:41:49 -0800284 synchronized (mLock) {
285 if (newState != mDockState) {
286 mDockState = newState;
Mike Lockwood924e1642010-03-05 11:56:53 -0500287 setCarModeLocked(mDockState == Intent.EXTRA_DOCK_STATE_CAR);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800288 if (mSystemReady) {
Dianne Hackbornf5c5d222010-04-09 13:14:48 -0700289 updateLocked(UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME, 0);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800290 }
291 }
292 }
293 }
Mike Lockwoode29db6a2010-03-05 13:45:51 -0500294
Jeff Brown487bb6e2012-10-11 13:35:42 -0700295 private static boolean isDeskDockState(int state) {
Daniel Sandler69a1da42011-11-04 15:08:30 -0400296 switch (state) {
297 case Intent.EXTRA_DOCK_STATE_DESK:
298 case Intent.EXTRA_DOCK_STATE_LE_DESK:
299 case Intent.EXTRA_DOCK_STATE_HE_DESK:
300 return true;
301 default:
302 return false;
303 }
304 }
305
Jeff Brown487bb6e2012-10-11 13:35:42 -0700306 private void updateConfigurationLocked() {
Jeff Brown62c82e42012-09-26 01:30:41 -0700307 int uiMode = mTelevision ? Configuration.UI_MODE_TYPE_TELEVISION : mDefaultUiModeType;
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800308 if (mCarModeEnabled) {
309 uiMode = Configuration.UI_MODE_TYPE_CAR;
Daniel Sandler69a1da42011-11-04 15:08:30 -0400310 } else if (isDeskDockState(mDockState)) {
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800311 uiMode = Configuration.UI_MODE_TYPE_DESK;
312 }
Dianne Hackborn9c9c5322010-03-30 23:12:22 -0700313 if (mCarModeEnabled) {
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800314 if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
Jeff Brown2416e092012-08-21 22:12:20 -0700315 updateComputedNightModeLocked();
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800316 uiMode |= mComputedNightMode ? Configuration.UI_MODE_NIGHT_YES
317 : Configuration.UI_MODE_NIGHT_NO;
318 } else {
319 uiMode |= mNightMode << 4;
320 }
321 } else {
322 // Disabling the car mode clears the night mode.
Daniel Sandler8daf2a42010-04-02 10:15:09 -0400323 uiMode = (uiMode & ~Configuration.UI_MODE_NIGHT_MASK) | Configuration.UI_MODE_NIGHT_NO;
324 }
325
326 if (LOG) {
John Spurlock960779d2012-05-29 14:37:05 -0400327 Slog.d(TAG,
328 "updateConfigurationLocked: mDockState=" + mDockState
Daniel Sandler8daf2a42010-04-02 10:15:09 -0400329 + "; mCarMode=" + mCarModeEnabled
330 + "; mNightMode=" + mNightMode
331 + "; uiMode=" + uiMode);
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800332 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100333
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800334 mCurUiMode = uiMode;
Jeff Brown62c82e42012-09-26 01:30:41 -0700335 if (!mHoldingConfiguration) {
Dianne Hackborn2ccda4d2010-03-22 21:49:15 -0700336 mConfiguration.uiMode = uiMode;
Jeff Brown62c82e42012-09-26 01:30:41 -0700337 }
338 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100339
Jeff Brown487bb6e2012-10-11 13:35:42 -0700340 private void sendConfigurationLocked() {
Jeff Brown62c82e42012-09-26 01:30:41 -0700341 if (mSetUiMode != mConfiguration.uiMode) {
342 mSetUiMode = mConfiguration.uiMode;
343
344 try {
345 ActivityManagerNative.getDefault().updateConfiguration(mConfiguration);
346 } catch (RemoteException e) {
347 Slog.w(TAG, "Failure communicating with activity manager", e);
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800348 }
349 }
350 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100351
Jeff Brown487bb6e2012-10-11 13:35:42 -0700352 private void updateLocked(int enableFlags, int disableFlags) {
353 String action = null;
354 String oldAction = null;
355 if (mLastBroadcastState == Intent.EXTRA_DOCK_STATE_CAR) {
356 adjustStatusBarCarModeLocked();
357 oldAction = UiModeManager.ACTION_EXIT_CAR_MODE;
358 } else if (isDeskDockState(mLastBroadcastState)) {
359 oldAction = UiModeManager.ACTION_EXIT_DESK_MODE;
360 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100361
Jeff Brown487bb6e2012-10-11 13:35:42 -0700362 if (mCarModeEnabled) {
363 if (mLastBroadcastState != Intent.EXTRA_DOCK_STATE_CAR) {
Tobias Haamel780b2602010-03-15 12:54:45 +0100364 adjustStatusBarCarModeLocked();
Jeff Brown487bb6e2012-10-11 13:35:42 -0700365
366 if (oldAction != null) {
367 mContext.sendBroadcastAsUser(new Intent(oldAction), UserHandle.ALL);
368 }
369 mLastBroadcastState = Intent.EXTRA_DOCK_STATE_CAR;
370 action = UiModeManager.ACTION_ENTER_CAR_MODE;
371 }
372 } else if (isDeskDockState(mDockState)) {
373 if (!isDeskDockState(mLastBroadcastState)) {
374 if (oldAction != null) {
375 mContext.sendBroadcastAsUser(new Intent(oldAction), UserHandle.ALL);
376 }
377 mLastBroadcastState = mDockState;
378 action = UiModeManager.ACTION_ENTER_DESK_MODE;
379 }
380 } else {
381 mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
382 action = oldAction;
383 }
384
385 if (action != null) {
386 if (LOG) {
387 Slog.v(TAG, String.format(
388 "updateLocked: preparing broadcast: action=%s enable=0x%08x disable=0x%08x",
389 action, enableFlags, disableFlags));
Dianne Hackborn7299c412010-03-04 18:41:49 -0800390 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100391
Jeff Brown487bb6e2012-10-11 13:35:42 -0700392 // Send the ordered broadcast; the result receiver will receive after all
393 // broadcasts have been sent. If any broadcast receiver changes the result
394 // code from the initial value of RESULT_OK, then the result receiver will
395 // not launch the corresponding dock application. This gives apps a chance
396 // to override the behavior and stay in their app even when the device is
397 // placed into a dock.
398 Intent intent = new Intent(action);
399 intent.putExtra("enableFlags", enableFlags);
400 intent.putExtra("disableFlags", disableFlags);
401 mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
402 mResultReceiver, null, Activity.RESULT_OK, null, null);
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100403
Jeff Brown487bb6e2012-10-11 13:35:42 -0700404 // Attempting to make this transition a little more clean, we are going
405 // to hold off on doing a configuration change until we have finished
406 // the broadcast and started the home activity.
407 mHoldingConfiguration = true;
408 updateConfigurationLocked();
409 } else {
410 String category = null;
411 if (mCarModeEnabled) {
412 if (ENABLE_LAUNCH_CAR_DOCK_APP
413 && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
414 category = Intent.CATEGORY_CAR_DOCK;
Dianne Hackborn7299c412010-03-04 18:41:49 -0800415 }
Daniel Sandler69a1da42011-11-04 15:08:30 -0400416 } else if (isDeskDockState(mDockState)) {
Jeff Brown487bb6e2012-10-11 13:35:42 -0700417 if (ENABLE_LAUNCH_DESK_DOCK_APP
418 && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
419 category = Intent.CATEGORY_DESK_DOCK;
Dianne Hackborn7299c412010-03-04 18:41:49 -0800420 }
421 } else {
Jeff Brown487bb6e2012-10-11 13:35:42 -0700422 if ((disableFlags & UiModeManager.DISABLE_CAR_MODE_GO_HOME) != 0) {
423 category = Intent.CATEGORY_HOME;
424 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800425 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100426
Jeff Brown487bb6e2012-10-11 13:35:42 -0700427 if (LOG) {
428 Slog.v(TAG, "updateLocked: null action, mDockState="
429 + mDockState +", category=" + category);
430 }
Daniel Sandler69a1da42011-11-04 15:08:30 -0400431
Jeff Brown487bb6e2012-10-11 13:35:42 -0700432 sendConfigurationAndStartDreamOrDockAppLocked(category);
433 }
Jeff Brown62c82e42012-09-26 01:30:41 -0700434
Jeff Brown487bb6e2012-10-11 13:35:42 -0700435 // keep screen on when charging and in car mode
436 boolean keepScreenOn = mCharging &&
437 ((mCarModeEnabled && mCarModeKeepsScreenOn) ||
438 (mCurUiMode == Configuration.UI_MODE_TYPE_DESK && mDeskModeKeepsScreenOn));
439 if (keepScreenOn != mWakeLock.isHeld()) {
440 if (keepScreenOn) {
441 mWakeLock.acquire();
Dianne Hackbornf5c5d222010-04-09 13:14:48 -0700442 } else {
Jeff Brown487bb6e2012-10-11 13:35:42 -0700443 mWakeLock.release();
Dianne Hackborn7299c412010-03-04 18:41:49 -0800444 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800445 }
446 }
447
Jeff Brown62c82e42012-09-26 01:30:41 -0700448 private void updateAfterBroadcastLocked(String action, int enableFlags, int disableFlags) {
449 // Launch a dock activity
450 String category = null;
451 if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(action)) {
452 // Only launch car home when car mode is enabled and the caller
453 // has asked us to switch to it.
454 if (ENABLE_LAUNCH_CAR_DOCK_APP
455 && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
456 category = Intent.CATEGORY_CAR_DOCK;
457 }
458 } else if (UiModeManager.ACTION_ENTER_DESK_MODE.equals(action)) {
459 // Only launch car home when desk mode is enabled and the caller
460 // has asked us to switch to it. Currently re-using the car
461 // mode flag since we don't have a formal API for "desk mode".
462 if (ENABLE_LAUNCH_DESK_DOCK_APP
463 && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
464 category = Intent.CATEGORY_DESK_DOCK;
465 }
466 } else {
467 // Launch the standard home app if requested.
468 if ((disableFlags & UiModeManager.DISABLE_CAR_MODE_GO_HOME) != 0) {
469 category = Intent.CATEGORY_HOME;
470 }
471 }
472
473 if (LOG) {
474 Slog.v(TAG, String.format(
475 "Handling broadcast result for action %s: enable=0x%08x, disable=0x%08x, "
476 + "category=%s",
477 action, enableFlags, disableFlags, category));
478 }
479
480 sendConfigurationAndStartDreamOrDockAppLocked(category);
481 }
482
483 private void sendConfigurationAndStartDreamOrDockAppLocked(String category) {
484 // Update the configuration but don't send it yet.
485 mHoldingConfiguration = false;
486 updateConfigurationLocked();
487
488 // Start the dock app, if there is one.
489 boolean dockAppStarted = false;
490 if (category != null) {
491 // Now we are going to be careful about switching the
492 // configuration and starting the activity -- we need to
493 // do this in a specific order under control of the
494 // activity manager, to do it cleanly. So compute the
495 // new config, but don't set it yet, and let the
496 // activity manager take care of both the start and config
497 // change.
498 Intent homeIntent = buildHomeIntent(category);
499 try {
500 int result = ActivityManagerNative.getDefault().startActivityWithConfig(
501 null, homeIntent, null, null, null, 0, 0,
502 mConfiguration, null, UserHandle.USER_CURRENT);
503 if (result >= ActivityManager.START_SUCCESS) {
504 dockAppStarted = true;
505 } else if (result != ActivityManager.START_INTENT_NOT_RESOLVED) {
506 Slog.e(TAG, "Could not start dock app: " + homeIntent
507 + ", startActivityWithConfig result " + result);
508 }
509 } catch (RemoteException ex) {
510 Slog.e(TAG, "Could not start dock app: " + homeIntent, ex);
511 }
512 }
513
514 // Send the new configuration.
515 sendConfigurationLocked();
516
517 // If we did not start a dock app, then start dreaming if supported.
Jeff Brownf9d40f42012-09-26 18:57:48 -0700518 if (category != null && !dockAppStarted
Jeff Brown487bb6e2012-10-11 13:35:42 -0700519 && isScreenSaverEnabledLocked() && isScreenSaverActivatedOnDockLocked()) {
Jeff Brown62c82e42012-09-26 01:30:41 -0700520 Slog.i(TAG, "Activating dream while docked.");
521 try {
522 IDreamManager dreamManagerService = IDreamManager.Stub.asInterface(
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700523 ServiceManager.getService(DreamService.DREAM_SERVICE));
Jeff Brown9fca9e92012-10-05 14:42:56 -0700524 if (dreamManagerService != null && !dreamManagerService.isDreaming()) {
525 // Wake up.
526 // The power manager will wake up the system when it starts receiving power
527 // but there is a race between that happening and the UI mode manager
528 // starting a dream. We want the system to already be awake
529 // by the time this happens. Otherwise the dream may not start.
530 mPowerManager.wakeUp(SystemClock.uptimeMillis());
531
532 // Dream.
533 dreamManagerService.dream();
534 }
Jeff Brown62c82e42012-09-26 01:30:41 -0700535 } catch (RemoteException ex) {
536 Slog.e(TAG, "Could not start dream when docked.", ex);
537 }
538 }
539 }
540
Jeff Brown487bb6e2012-10-11 13:35:42 -0700541 private boolean isScreenSaverEnabledLocked() {
Jeff Brown62c82e42012-09-26 01:30:41 -0700542 return Settings.Secure.getIntForUser(mContext.getContentResolver(),
543 Settings.Secure.SCREENSAVER_ENABLED, DEFAULT_SCREENSAVER_ENABLED,
544 UserHandle.USER_CURRENT) != 0;
545 }
546
Jeff Brown487bb6e2012-10-11 13:35:42 -0700547 private boolean isScreenSaverActivatedOnDockLocked() {
Jeff Brown62c82e42012-09-26 01:30:41 -0700548 return Settings.Secure.getIntForUser(mContext.getContentResolver(),
549 Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
550 DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK, UserHandle.USER_CURRENT) != 0;
551 }
552
Dianne Hackborn7299c412010-03-04 18:41:49 -0800553 private void adjustStatusBarCarModeLocked() {
554 if (mStatusBarManager == null) {
Jeff Brown487bb6e2012-10-11 13:35:42 -0700555 mStatusBarManager = (StatusBarManager)
556 mContext.getSystemService(Context.STATUS_BAR_SERVICE);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800557 }
558
Joe Onorato089de882010-04-12 08:18:45 -0700559 // Fear not: StatusBarManagerService manages a list of requests to disable
Dianne Hackborn7299c412010-03-04 18:41:49 -0800560 // features of the status bar; these are ORed together to form the
561 // active disabled list. So if (for example) the device is locked and
562 // the status bar should be totally disabled, the calls below will
563 // have no effect until the device is unlocked.
564 if (mStatusBarManager != null) {
565 mStatusBarManager.disable(mCarModeEnabled
566 ? StatusBarManager.DISABLE_NOTIFICATION_TICKER
567 : StatusBarManager.DISABLE_NONE);
568 }
569
570 if (mNotificationManager == null) {
571 mNotificationManager = (NotificationManager)
572 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
573 }
574
575 if (mNotificationManager != null) {
576 if (mCarModeEnabled) {
577 Intent carModeOffIntent = new Intent(mContext, DisableCarModeActivity.class);
578
579 Notification n = new Notification();
580 n.icon = R.drawable.stat_notify_car_mode;
581 n.defaults = Notification.DEFAULT_LIGHTS;
582 n.flags = Notification.FLAG_ONGOING_EVENT;
583 n.when = 0;
584 n.setLatestEventInfo(
585 mContext,
586 mContext.getString(R.string.car_mode_disable_notification_title),
587 mContext.getString(R.string.car_mode_disable_notification_message),
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700588 PendingIntent.getActivityAsUser(mContext, 0, carModeOffIntent, 0,
589 null, UserHandle.CURRENT));
590 mNotificationManager.notifyAsUser(null,
591 R.string.car_mode_disable_notification_title, n, UserHandle.ALL);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800592 } else {
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700593 mNotificationManager.cancelAsUser(null,
594 R.string.car_mode_disable_notification_title, UserHandle.ALL);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800595 }
596 }
597 }
598
Jeff Brown2416e092012-08-21 22:12:20 -0700599 private void updateTwilight() {
600 synchronized (mLock) {
Jeff Brown487bb6e2012-10-11 13:35:42 -0700601 if (isDoingNightModeLocked() && mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
Jeff Brown2416e092012-08-21 22:12:20 -0700602 updateComputedNightModeLocked();
603 updateLocked(0, 0);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800604 }
605 }
Jeff Brown2416e092012-08-21 22:12:20 -0700606 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800607
Jeff Brown2416e092012-08-21 22:12:20 -0700608 private void updateComputedNightModeLocked() {
609 TwilightState state = mTwilightService.getCurrentState();
610 if (state != null) {
611 mComputedNightMode = state.isNight();
Dianne Hackborn7299c412010-03-04 18:41:49 -0800612 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800613 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100614
Dianne Hackborn7299c412010-03-04 18:41:49 -0800615 @Override
616 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
617 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
618 != PackageManager.PERMISSION_GRANTED) {
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100619
Dianne Hackborn7299c412010-03-04 18:41:49 -0800620 pw.println("Permission Denial: can't dump uimode service from from pid="
621 + Binder.getCallingPid()
622 + ", uid=" + Binder.getCallingUid());
623 return;
624 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100625
Dianne Hackborn7299c412010-03-04 18:41:49 -0800626 synchronized (mLock) {
627 pw.println("Current UI Mode Service state:");
628 pw.print(" mDockState="); pw.print(mDockState);
629 pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState);
630 pw.print(" mNightMode="); pw.print(mNightMode);
631 pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled);
632 pw.print(" mComputedNightMode="); pw.println(mComputedNightMode);
633 pw.print(" mCurUiMode=0x"); pw.print(Integer.toHexString(mCurUiMode));
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800634 pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode));
635 pw.print(" mHoldingConfiguration="); pw.print(mHoldingConfiguration);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800636 pw.print(" mSystemReady="); pw.println(mSystemReady);
Jeff Brown2416e092012-08-21 22:12:20 -0700637 pw.print(" mTwilightService.getCurrentState()=");
638 pw.println(mTwilightService.getCurrentState());
Dianne Hackborn7299c412010-03-04 18:41:49 -0800639 }
640 }
641}