blob: 2825cf9d867b477befb32455989069745ecde47c [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
Justin Klaassen908b86c2016-08-08 09:18:42 -070019import android.annotation.Nullable;
Dianne Hackborn7299c412010-03-04 18:41:49 -080020import android.app.Activity;
Jeff Brown62c82e42012-09-26 01:30:41 -070021import android.app.ActivityManager;
Dianne Hackborn7299c412010-03-04 18:41:49 -080022import android.app.ActivityManagerNative;
Dianne Hackborn7299c412010-03-04 18:41:49 -080023import android.app.IUiModeManager;
24import android.app.Notification;
25import android.app.NotificationManager;
26import android.app.PendingIntent;
27import android.app.StatusBarManager;
28import android.app.UiModeManager;
Dianne Hackborn7299c412010-03-04 18:41:49 -080029import android.content.BroadcastReceiver;
30import android.content.Context;
31import android.content.Intent;
32import android.content.IntentFilter;
33import android.content.pm.PackageManager;
34import android.content.res.Configuration;
Alan Viverette4cc1e9e2015-02-12 11:01:06 -080035import android.content.res.Resources;
Mike Lockwoode29db6a2010-03-05 13:45:51 -050036import android.os.BatteryManager;
Dianne Hackborn7299c412010-03-04 18:41:49 -080037import android.os.Binder;
Dianne Hackborn7299c412010-03-04 18:41:49 -080038import android.os.Handler;
Adam Lesinski182f73f2013-12-05 16:48:06 -080039import android.os.IBinder;
Mike Lockwoode29db6a2010-03-05 13:45:51 -050040import android.os.PowerManager;
Dianne Hackborn7299c412010-03-04 18:41:49 -080041import android.os.RemoteException;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070042import android.os.UserHandle;
Dianne Hackborn2ccda4d2010-03-22 21:49:15 -070043import android.provider.Settings;
Jeff Brown11159e92012-10-11 15:58:37 -070044import android.service.dreams.Sandman;
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;
Adam Lesinski182f73f2013-12-05 16:48:06 -080052import com.android.server.twilight.TwilightListener;
53import com.android.server.twilight.TwilightManager;
54import com.android.server.twilight.TwilightState;
Dianne Hackborn7299c412010-03-04 18:41:49 -080055
Adam Lesinski182f73f2013-12-05 16:48:06 -080056final class UiModeManagerService extends SystemService {
Dianne Hackborn7299c412010-03-04 18:41:49 -080057 private static final String TAG = UiModeManager.class.getSimpleName();
58 private static final boolean LOG = false;
59
Daniel Sandler11ddf532011-11-16 11:10:03 -080060 // Enable launching of applications when entering the dock.
John Spurlock960779d2012-05-29 14:37:05 -040061 private static final boolean ENABLE_LAUNCH_DESK_DOCK_APP = true;
Daniel Sandler11ddf532011-11-16 11:10:03 -080062
Dianne Hackborn7299c412010-03-04 18:41:49 -080063 final Object mLock = new Object();
Dianne Hackborn7299c412010-03-04 18:41:49 -080064 private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
Bernd Holzheyba9ab182010-03-12 09:30:29 +010065
Adam Lesinski182f73f2013-12-05 16:48:06 -080066 private int mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
Alan Viverette4cc1e9e2015-02-12 11:01:06 -080067 private int mNightMode = UiModeManager.MODE_NIGHT_NO;
Adam Lesinski182f73f2013-12-05 16:48:06 -080068
Dianne Hackborn7299c412010-03-04 18:41:49 -080069 private boolean mCarModeEnabled = false;
Mike Lockwoode29db6a2010-03-05 13:45:51 -050070 private boolean mCharging = false;
Adam Lesinski182f73f2013-12-05 16:48:06 -080071 private int mDefaultUiModeType;
72 private boolean mCarModeKeepsScreenOn;
73 private boolean mDeskModeKeepsScreenOn;
74 private boolean mTelevision;
John Spurlock6c191292014-04-03 16:37:27 -040075 private boolean mWatch;
Dianne Hackborn7299c412010-03-04 18:41:49 -080076 private boolean mComputedNightMode;
keunyoung1d0a7cc2014-07-28 13:12:50 -070077 private int mCarModeEnableFlags;
Adam Lesinski182f73f2013-12-05 16:48:06 -080078
keunyounga7710492015-09-23 11:33:58 -070079 // flag set by resource, whether to enable Car dock launch when starting car mode.
80 private boolean mEnableCarDockLaunch = true;
81 // flag set by resource, whether to lock UI mode to the default one or not.
82 private boolean mUiModeLocked = false;
83 // flag set by resource, whether to night mode change for normal all or not.
84 private boolean mNightModeLocked = false;
85
Adam Lesinski182f73f2013-12-05 16:48:06 -080086 int mCurUiMode = 0;
Dianne Hackbornb8b11a02010-03-10 15:53:11 -080087 private int mSetUiMode = 0;
Dianne Hackbornb8b11a02010-03-10 15:53:11 -080088 private boolean mHoldingConfiguration = false;
Adam Lesinski182f73f2013-12-05 16:48:06 -080089
Dianne Hackborn7299c412010-03-04 18:41:49 -080090 private Configuration mConfiguration = new Configuration();
Adam Lesinski182f73f2013-12-05 16:48:06 -080091 boolean mSystemReady;
Bernd Holzheyba9ab182010-03-12 09:30:29 +010092
Adam Lesinski182f73f2013-12-05 16:48:06 -080093 private final Handler mHandler = new Handler();
Dianne Hackborn7299c412010-03-04 18:41:49 -080094
Adam Lesinski182f73f2013-12-05 16:48:06 -080095 private TwilightManager mTwilightManager;
Dianne Hackborn7299c412010-03-04 18:41:49 -080096 private NotificationManager mNotificationManager;
Dianne Hackborn7299c412010-03-04 18:41:49 -080097 private StatusBarManager mStatusBarManager;
Jeff Brown9fca9e92012-10-05 14:42:56 -070098
Adam Lesinski182f73f2013-12-05 16:48:06 -080099 private PowerManager.WakeLock mWakeLock;
Dianne Hackborn7299c412010-03-04 18:41:49 -0800100
Jeff Brownb880d882014-02-10 19:47:07 -0800101 public UiModeManagerService(Context context) {
102 super(context);
103 }
104
Adam Lesinski182f73f2013-12-05 16:48:06 -0800105 private static Intent buildHomeIntent(String category) {
Dianne Hackbornf5c5d222010-04-09 13:14:48 -0700106 Intent intent = new Intent(Intent.ACTION_MAIN);
107 intent.addCategory(category);
108 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
109 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
110 return intent;
111 }
John Spurlock960779d2012-05-29 14:37:05 -0400112
Dianne Hackborn7299c412010-03-04 18:41:49 -0800113 // The broadcast receiver which receives the result of the ordered broadcast sent when
114 // the dock state changes. The original ordered broadcast is sent with an initial result
115 // code of RESULT_OK. If any of the registered broadcast receivers changes this value, e.g.,
116 // to RESULT_CANCELED, then the intent to start a dock app will not be sent.
117 private final BroadcastReceiver mResultReceiver = new BroadcastReceiver() {
118 @Override
119 public void onReceive(Context context, Intent intent) {
120 if (getResultCode() != Activity.RESULT_OK) {
Daniel Sandler69a1da42011-11-04 15:08:30 -0400121 if (LOG) {
John Spurlock960779d2012-05-29 14:37:05 -0400122 Slog.v(TAG, "Handling broadcast result for action " + intent.getAction()
Daniel Sandler69a1da42011-11-04 15:08:30 -0400123 + ": canceled: " + getResultCode());
124 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800125 return;
126 }
127
Jeff Brown62c82e42012-09-26 01:30:41 -0700128 final int enableFlags = intent.getIntExtra("enableFlags", 0);
129 final int disableFlags = intent.getIntExtra("disableFlags", 0);
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800130 synchronized (mLock) {
Jeff Brown62c82e42012-09-26 01:30:41 -0700131 updateAfterBroadcastLocked(intent.getAction(), enableFlags, disableFlags);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800132 }
133 }
134 };
135
Dianne Hackborn7299c412010-03-04 18:41:49 -0800136 private final BroadcastReceiver mDockModeReceiver = new BroadcastReceiver() {
137 @Override
138 public void onReceive(Context context, Intent intent) {
139 int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
140 Intent.EXTRA_DOCK_STATE_UNDOCKED);
141 updateDockState(state);
142 }
143 };
144
Mike Lockwoode29db6a2010-03-05 13:45:51 -0500145 private final BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() {
146 @Override
147 public void onReceive(Context context, Intent intent) {
148 mCharging = (intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0);
149 synchronized (mLock) {
150 if (mSystemReady) {
Dianne Hackbornf5c5d222010-04-09 13:14:48 -0700151 updateLocked(0, 0);
Mike Lockwoode29db6a2010-03-05 13:45:51 -0500152 }
153 }
154 }
155 };
156
Adam Lesinski182f73f2013-12-05 16:48:06 -0800157 private final TwilightListener mTwilightListener = new TwilightListener() {
Dianne Hackborn57f45032010-06-17 15:49:33 -0700158 @Override
Justin Klaassen908b86c2016-08-08 09:18:42 -0700159 public void onTwilightStateChanged(@Nullable TwilightState state) {
160 synchronized (mLock) {
161 if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
162 updateComputedNightModeLocked();
163 updateLocked(0, 0);
164 }
165 }
Dianne Hackborn57f45032010-06-17 15:49:33 -0700166 }
167 };
168
Adam Lesinski182f73f2013-12-05 16:48:06 -0800169 @Override
170 public void onStart() {
171 final Context context = getContext();
Alan Viverette4cc1e9e2015-02-12 11:01:06 -0800172
Adam Lesinski182f73f2013-12-05 16:48:06 -0800173 final PowerManager powerManager =
174 (PowerManager) context.getSystemService(Context.POWER_SERVICE);
175 mWakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800176
Adam Lesinski182f73f2013-12-05 16:48:06 -0800177 context.registerReceiver(mDockModeReceiver,
Dianne Hackborn7299c412010-03-04 18:41:49 -0800178 new IntentFilter(Intent.ACTION_DOCK_EVENT));
Adam Lesinski182f73f2013-12-05 16:48:06 -0800179 context.registerReceiver(mBatteryReceiver,
Mike Lockwoode29db6a2010-03-05 13:45:51 -0500180 new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
181
Dianne Hackborn7299c412010-03-04 18:41:49 -0800182 mConfiguration.setToDefaults();
Mike Lockwoode29db6a2010-03-05 13:45:51 -0500183
Alan Viverette4cc1e9e2015-02-12 11:01:06 -0800184 final Resources res = context.getResources();
185 mDefaultUiModeType = res.getInteger(
Joe Onorato44fcb832011-12-14 20:59:30 -0800186 com.android.internal.R.integer.config_defaultUiModeType);
Alan Viverette4cc1e9e2015-02-12 11:01:06 -0800187 mCarModeKeepsScreenOn = (res.getInteger(
Mike Lockwoode29db6a2010-03-05 13:45:51 -0500188 com.android.internal.R.integer.config_carDockKeepsScreenOn) == 1);
Alan Viverette4cc1e9e2015-02-12 11:01:06 -0800189 mDeskModeKeepsScreenOn = (res.getInteger(
Mike Lockwoode29db6a2010-03-05 13:45:51 -0500190 com.android.internal.R.integer.config_deskDockKeepsScreenOn) == 1);
keunyounga7710492015-09-23 11:33:58 -0700191 mEnableCarDockLaunch = res.getBoolean(
192 com.android.internal.R.bool.config_enableCarDockHomeLaunch);
193 mUiModeLocked = res.getBoolean(com.android.internal.R.bool.config_lockUiMode);
194 mNightModeLocked = res.getBoolean(com.android.internal.R.bool.config_lockDayNightMode);
Dianne Hackborn0cf2c8a2012-05-17 17:29:49 -0700195
Alan Viverette4cc1e9e2015-02-12 11:01:06 -0800196 final PackageManager pm = context.getPackageManager();
197 mTelevision = pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION)
198 || pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
199 mWatch = pm.hasSystemFeature(PackageManager.FEATURE_WATCH);
200
201 final int defaultNightMode = res.getInteger(
202 com.android.internal.R.integer.config_defaultNightMode);
Adam Lesinski182f73f2013-12-05 16:48:06 -0800203 mNightMode = Settings.Secure.getInt(context.getContentResolver(),
Alan Viverette4cc1e9e2015-02-12 11:01:06 -0800204 Settings.Secure.UI_NIGHT_MODE, defaultNightMode);
Jeff Brown2416e092012-08-21 22:12:20 -0700205
Adam Lesinski05199e82015-03-19 14:37:11 -0700206 // Update the initial, static configurations.
207 synchronized (this) {
208 updateConfigurationLocked();
209 sendConfigurationLocked();
210 }
Adam Lesinski182f73f2013-12-05 16:48:06 -0800211
212 publishBinderService(Context.UI_MODE_SERVICE, mService);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800213 }
214
Adam Lesinski182f73f2013-12-05 16:48:06 -0800215 private final IBinder mService = new IUiModeManager.Stub() {
216 @Override
217 public void enableCarMode(int flags) {
keunyounga7710492015-09-23 11:33:58 -0700218 if (isUiModeLocked()) {
219 Slog.e(TAG, "enableCarMode while UI mode is locked");
220 return;
221 }
Adam Lesinski182f73f2013-12-05 16:48:06 -0800222 final long ident = Binder.clearCallingIdentity();
223 try {
224 synchronized (mLock) {
keunyoung1d0a7cc2014-07-28 13:12:50 -0700225 setCarModeLocked(true, flags);
Adam Lesinski182f73f2013-12-05 16:48:06 -0800226 if (mSystemReady) {
227 updateLocked(flags, 0);
228 }
Jeff Brown487bb6e2012-10-11 13:35:42 -0700229 }
Adam Lesinski182f73f2013-12-05 16:48:06 -0800230 } finally {
231 Binder.restoreCallingIdentity(ident);
Mike Lockwood924e1642010-03-05 11:56:53 -0500232 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800233 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800234
Adam Lesinski182f73f2013-12-05 16:48:06 -0800235 @Override
236 public void disableCarMode(int flags) {
keunyounga7710492015-09-23 11:33:58 -0700237 if (isUiModeLocked()) {
238 Slog.e(TAG, "disableCarMode while UI mode is locked");
239 return;
240 }
Adam Lesinski182f73f2013-12-05 16:48:06 -0800241 final long ident = Binder.clearCallingIdentity();
242 try {
243 synchronized (mLock) {
keunyoung1d0a7cc2014-07-28 13:12:50 -0700244 setCarModeLocked(false, 0);
Adam Lesinski182f73f2013-12-05 16:48:06 -0800245 if (mSystemReady) {
246 updateLocked(0, flags);
247 }
Jeff Brown487bb6e2012-10-11 13:35:42 -0700248 }
Adam Lesinski182f73f2013-12-05 16:48:06 -0800249 } finally {
250 Binder.restoreCallingIdentity(ident);
Mike Lockwood924e1642010-03-05 11:56:53 -0500251 }
Jeff Brown487bb6e2012-10-11 13:35:42 -0700252 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100253
Adam Lesinski182f73f2013-12-05 16:48:06 -0800254 @Override
255 public int getCurrentModeType() {
256 final long ident = Binder.clearCallingIdentity();
257 try {
258 synchronized (mLock) {
259 return mCurUiMode & Configuration.UI_MODE_TYPE_MASK;
Jeff Brown487bb6e2012-10-11 13:35:42 -0700260 }
Adam Lesinski182f73f2013-12-05 16:48:06 -0800261 } finally {
262 Binder.restoreCallingIdentity(ident);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800263 }
264 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100265
Adam Lesinski182f73f2013-12-05 16:48:06 -0800266 @Override
267 public void setNightMode(int mode) {
keunyounga7710492015-09-23 11:33:58 -0700268 if (isNightModeLocked() && (getContext().checkCallingOrSelfPermission(
269 android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)
270 != PackageManager.PERMISSION_GRANTED)) {
271 Slog.e(TAG,
272 "Night mode locked, requires MODIFY_DAY_NIGHT_MODE permission");
273 return;
274 }
Adam Lesinski182f73f2013-12-05 16:48:06 -0800275 switch (mode) {
276 case UiModeManager.MODE_NIGHT_NO:
277 case UiModeManager.MODE_NIGHT_YES:
278 case UiModeManager.MODE_NIGHT_AUTO:
279 break;
280 default:
281 throw new IllegalArgumentException("Unknown mode: " + mode);
282 }
283
284 final long ident = Binder.clearCallingIdentity();
285 try {
286 synchronized (mLock) {
Alan Viverette4cc1e9e2015-02-12 11:01:06 -0800287 if (mNightMode != mode) {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800288 Settings.Secure.putInt(getContext().getContentResolver(),
289 Settings.Secure.UI_NIGHT_MODE, mode);
290 mNightMode = mode;
291 updateLocked(0, 0);
292 }
293 }
294 } finally {
295 Binder.restoreCallingIdentity(ident);
296 }
297 }
298
299 @Override
300 public int getNightMode() {
301 synchronized (mLock) {
302 return mNightMode;
303 }
304 }
305
306 @Override
keunyounga7710492015-09-23 11:33:58 -0700307 public boolean isUiModeLocked() {
308 synchronized (mLock) {
309 return mUiModeLocked;
310 }
311 }
312
313 @Override
314 public boolean isNightModeLocked() {
315 synchronized (mLock) {
316 return mNightModeLocked;
317 }
318 }
319
320 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -0800321 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
322 if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
323 != PackageManager.PERMISSION_GRANTED) {
324
325 pw.println("Permission Denial: can't dump uimode service from from pid="
326 + Binder.getCallingPid()
327 + ", uid=" + Binder.getCallingUid());
328 return;
329 }
330
331 dumpImpl(pw);
332 }
333 };
334
335 void dumpImpl(PrintWriter pw) {
Jeff Brown487bb6e2012-10-11 13:35:42 -0700336 synchronized (mLock) {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800337 pw.println("Current UI Mode Service state:");
338 pw.print(" mDockState="); pw.print(mDockState);
339 pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState);
340 pw.print(" mNightMode="); pw.print(mNightMode);
keunyounga7710492015-09-23 11:33:58 -0700341 pw.print(" mNightModeLocked="); pw.print(mNightModeLocked);
Adam Lesinski182f73f2013-12-05 16:48:06 -0800342 pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled);
keunyoung1d0a7cc2014-07-28 13:12:50 -0700343 pw.print(" mComputedNightMode="); pw.print(mComputedNightMode);
keunyounga7710492015-09-23 11:33:58 -0700344 pw.print(" mCarModeEnableFlags="); pw.print(mCarModeEnableFlags);
345 pw.print(" mEnableCarDockLaunch="); pw.println(mEnableCarDockLaunch);
Adam Lesinski182f73f2013-12-05 16:48:06 -0800346 pw.print(" mCurUiMode=0x"); pw.print(Integer.toHexString(mCurUiMode));
keunyounga7710492015-09-23 11:33:58 -0700347 pw.print(" mUiModeLocked="); pw.print(mUiModeLocked);
Adam Lesinski182f73f2013-12-05 16:48:06 -0800348 pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode));
349 pw.print(" mHoldingConfiguration="); pw.print(mHoldingConfiguration);
350 pw.print(" mSystemReady="); pw.println(mSystemReady);
Adam Lesinski05199e82015-03-19 14:37:11 -0700351 if (mTwilightManager != null) {
352 // We may not have a TwilightManager.
Justin Klaassen908b86c2016-08-08 09:18:42 -0700353 pw.print(" mTwilightService.getLastTwilightState()=");
354 pw.println(mTwilightManager.getLastTwilightState());
Adam Lesinski05199e82015-03-19 14:37:11 -0700355 }
Jeff Brown487bb6e2012-10-11 13:35:42 -0700356 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800357 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100358
Adam Lesinski182f73f2013-12-05 16:48:06 -0800359 @Override
360 public void onBootPhase(int phase) {
361 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
362 synchronized (mLock) {
Adam Lesinski05199e82015-03-19 14:37:11 -0700363 mTwilightManager = getLocalService(TwilightManager.class);
Adam Lesinski182f73f2013-12-05 16:48:06 -0800364 mSystemReady = true;
365 mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR;
366 updateComputedNightModeLocked();
367 updateLocked(0, 0);
368 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800369 }
370 }
371
keunyoung1d0a7cc2014-07-28 13:12:50 -0700372 void setCarModeLocked(boolean enabled, int flags) {
Dianne Hackborn7299c412010-03-04 18:41:49 -0800373 if (mCarModeEnabled != enabled) {
374 mCarModeEnabled = enabled;
Dianne Hackborn7299c412010-03-04 18:41:49 -0800375 }
keunyoung1d0a7cc2014-07-28 13:12:50 -0700376 mCarModeEnableFlags = flags;
Dianne Hackborn7299c412010-03-04 18:41:49 -0800377 }
378
Jeff Brown487bb6e2012-10-11 13:35:42 -0700379 private void updateDockState(int newState) {
Dianne Hackborn7299c412010-03-04 18:41:49 -0800380 synchronized (mLock) {
381 if (newState != mDockState) {
382 mDockState = newState;
keunyoung1d0a7cc2014-07-28 13:12:50 -0700383 setCarModeLocked(mDockState == Intent.EXTRA_DOCK_STATE_CAR, 0);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800384 if (mSystemReady) {
Dianne Hackbornf5c5d222010-04-09 13:14:48 -0700385 updateLocked(UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME, 0);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800386 }
387 }
388 }
389 }
Mike Lockwoode29db6a2010-03-05 13:45:51 -0500390
Jeff Brown487bb6e2012-10-11 13:35:42 -0700391 private static boolean isDeskDockState(int state) {
Daniel Sandler69a1da42011-11-04 15:08:30 -0400392 switch (state) {
393 case Intent.EXTRA_DOCK_STATE_DESK:
394 case Intent.EXTRA_DOCK_STATE_LE_DESK:
395 case Intent.EXTRA_DOCK_STATE_HE_DESK:
396 return true;
397 default:
398 return false;
399 }
400 }
401
Jeff Brown487bb6e2012-10-11 13:35:42 -0700402 private void updateConfigurationLocked() {
John Spurlock6c191292014-04-03 16:37:27 -0400403 int uiMode = mDefaultUiModeType;
keunyounga7710492015-09-23 11:33:58 -0700404 if (mUiModeLocked) {
405 // no-op, keeps default one
406 } else if (mTelevision) {
John Spurlock6c191292014-04-03 16:37:27 -0400407 uiMode = Configuration.UI_MODE_TYPE_TELEVISION;
408 } else if (mWatch) {
409 uiMode = Configuration.UI_MODE_TYPE_WATCH;
410 } else if (mCarModeEnabled) {
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800411 uiMode = Configuration.UI_MODE_TYPE_CAR;
Daniel Sandler69a1da42011-11-04 15:08:30 -0400412 } else if (isDeskDockState(mDockState)) {
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800413 uiMode = Configuration.UI_MODE_TYPE_DESK;
414 }
Alan Viverette4cc1e9e2015-02-12 11:01:06 -0800415
416 if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
Justin Klaassen908b86c2016-08-08 09:18:42 -0700417 if (mTwilightManager != null) {
418 mTwilightManager.registerListener(mTwilightListener, mHandler);
419 }
Alan Viverette4cc1e9e2015-02-12 11:01:06 -0800420 updateComputedNightModeLocked();
421 uiMode |= mComputedNightMode ? Configuration.UI_MODE_NIGHT_YES
422 : Configuration.UI_MODE_NIGHT_NO;
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800423 } else {
Justin Klaassen908b86c2016-08-08 09:18:42 -0700424 if (mTwilightManager != null) {
425 mTwilightManager.unregisterListener(mTwilightListener);
426 }
Alan Viverette4cc1e9e2015-02-12 11:01:06 -0800427 uiMode |= mNightMode << 4;
Daniel Sandler8daf2a42010-04-02 10:15:09 -0400428 }
429
430 if (LOG) {
John Spurlock960779d2012-05-29 14:37:05 -0400431 Slog.d(TAG,
432 "updateConfigurationLocked: mDockState=" + mDockState
Daniel Sandler8daf2a42010-04-02 10:15:09 -0400433 + "; mCarMode=" + mCarModeEnabled
434 + "; mNightMode=" + mNightMode
435 + "; uiMode=" + uiMode);
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800436 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100437
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800438 mCurUiMode = uiMode;
Jeff Brown62c82e42012-09-26 01:30:41 -0700439 if (!mHoldingConfiguration) {
Dianne Hackborn2ccda4d2010-03-22 21:49:15 -0700440 mConfiguration.uiMode = uiMode;
Jeff Brown62c82e42012-09-26 01:30:41 -0700441 }
442 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100443
Jeff Brown487bb6e2012-10-11 13:35:42 -0700444 private void sendConfigurationLocked() {
Jeff Brown62c82e42012-09-26 01:30:41 -0700445 if (mSetUiMode != mConfiguration.uiMode) {
446 mSetUiMode = mConfiguration.uiMode;
447
448 try {
449 ActivityManagerNative.getDefault().updateConfiguration(mConfiguration);
450 } catch (RemoteException e) {
451 Slog.w(TAG, "Failure communicating with activity manager", e);
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800452 }
453 }
454 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100455
Adam Lesinski182f73f2013-12-05 16:48:06 -0800456 void updateLocked(int enableFlags, int disableFlags) {
Jeff Brown487bb6e2012-10-11 13:35:42 -0700457 String action = null;
458 String oldAction = null;
459 if (mLastBroadcastState == Intent.EXTRA_DOCK_STATE_CAR) {
460 adjustStatusBarCarModeLocked();
461 oldAction = UiModeManager.ACTION_EXIT_CAR_MODE;
462 } else if (isDeskDockState(mLastBroadcastState)) {
463 oldAction = UiModeManager.ACTION_EXIT_DESK_MODE;
464 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100465
Jeff Brown487bb6e2012-10-11 13:35:42 -0700466 if (mCarModeEnabled) {
467 if (mLastBroadcastState != Intent.EXTRA_DOCK_STATE_CAR) {
Tobias Haamel780b2602010-03-15 12:54:45 +0100468 adjustStatusBarCarModeLocked();
Jeff Brown487bb6e2012-10-11 13:35:42 -0700469 if (oldAction != null) {
Adrian Roos2fbf4d52016-10-20 14:40:51 -0700470 sendForegroundBroadcastToAllUsers(oldAction);
Jeff Brown487bb6e2012-10-11 13:35:42 -0700471 }
472 mLastBroadcastState = Intent.EXTRA_DOCK_STATE_CAR;
473 action = UiModeManager.ACTION_ENTER_CAR_MODE;
474 }
475 } else if (isDeskDockState(mDockState)) {
476 if (!isDeskDockState(mLastBroadcastState)) {
477 if (oldAction != null) {
Adrian Roos2fbf4d52016-10-20 14:40:51 -0700478 sendForegroundBroadcastToAllUsers(oldAction);
Jeff Brown487bb6e2012-10-11 13:35:42 -0700479 }
480 mLastBroadcastState = mDockState;
481 action = UiModeManager.ACTION_ENTER_DESK_MODE;
482 }
483 } else {
484 mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
485 action = oldAction;
486 }
487
488 if (action != null) {
489 if (LOG) {
490 Slog.v(TAG, String.format(
491 "updateLocked: preparing broadcast: action=%s enable=0x%08x disable=0x%08x",
492 action, enableFlags, disableFlags));
Dianne Hackborn7299c412010-03-04 18:41:49 -0800493 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100494
Jeff Brown487bb6e2012-10-11 13:35:42 -0700495 // Send the ordered broadcast; the result receiver will receive after all
496 // broadcasts have been sent. If any broadcast receiver changes the result
497 // code from the initial value of RESULT_OK, then the result receiver will
498 // not launch the corresponding dock application. This gives apps a chance
499 // to override the behavior and stay in their app even when the device is
500 // placed into a dock.
501 Intent intent = new Intent(action);
502 intent.putExtra("enableFlags", enableFlags);
503 intent.putExtra("disableFlags", disableFlags);
Adrian Roos2fbf4d52016-10-20 14:40:51 -0700504 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Adam Lesinski182f73f2013-12-05 16:48:06 -0800505 getContext().sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
Jeff Brown487bb6e2012-10-11 13:35:42 -0700506 mResultReceiver, null, Activity.RESULT_OK, null, null);
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100507
Jeff Brown487bb6e2012-10-11 13:35:42 -0700508 // Attempting to make this transition a little more clean, we are going
509 // to hold off on doing a configuration change until we have finished
510 // the broadcast and started the home activity.
511 mHoldingConfiguration = true;
512 updateConfigurationLocked();
513 } else {
514 String category = null;
515 if (mCarModeEnabled) {
keunyounga7710492015-09-23 11:33:58 -0700516 if (mEnableCarDockLaunch
Jeff Brown487bb6e2012-10-11 13:35:42 -0700517 && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
518 category = Intent.CATEGORY_CAR_DOCK;
Dianne Hackborn7299c412010-03-04 18:41:49 -0800519 }
Daniel Sandler69a1da42011-11-04 15:08:30 -0400520 } else if (isDeskDockState(mDockState)) {
Jeff Brown487bb6e2012-10-11 13:35:42 -0700521 if (ENABLE_LAUNCH_DESK_DOCK_APP
522 && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
523 category = Intent.CATEGORY_DESK_DOCK;
Dianne Hackborn7299c412010-03-04 18:41:49 -0800524 }
525 } else {
Jeff Brown487bb6e2012-10-11 13:35:42 -0700526 if ((disableFlags & UiModeManager.DISABLE_CAR_MODE_GO_HOME) != 0) {
527 category = Intent.CATEGORY_HOME;
528 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800529 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100530
Jeff Brown487bb6e2012-10-11 13:35:42 -0700531 if (LOG) {
532 Slog.v(TAG, "updateLocked: null action, mDockState="
533 + mDockState +", category=" + category);
534 }
Daniel Sandler69a1da42011-11-04 15:08:30 -0400535
Jeff Brown487bb6e2012-10-11 13:35:42 -0700536 sendConfigurationAndStartDreamOrDockAppLocked(category);
537 }
Jeff Brown62c82e42012-09-26 01:30:41 -0700538
Jeff Brown487bb6e2012-10-11 13:35:42 -0700539 // keep screen on when charging and in car mode
540 boolean keepScreenOn = mCharging &&
keunyoung1d0a7cc2014-07-28 13:12:50 -0700541 ((mCarModeEnabled && mCarModeKeepsScreenOn &&
keunyoungc093bf22014-08-11 18:51:15 -0700542 (mCarModeEnableFlags & UiModeManager.ENABLE_CAR_MODE_ALLOW_SLEEP) == 0) ||
Jeff Brown487bb6e2012-10-11 13:35:42 -0700543 (mCurUiMode == Configuration.UI_MODE_TYPE_DESK && mDeskModeKeepsScreenOn));
544 if (keepScreenOn != mWakeLock.isHeld()) {
545 if (keepScreenOn) {
546 mWakeLock.acquire();
Dianne Hackbornf5c5d222010-04-09 13:14:48 -0700547 } else {
Jeff Brown487bb6e2012-10-11 13:35:42 -0700548 mWakeLock.release();
Dianne Hackborn7299c412010-03-04 18:41:49 -0800549 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800550 }
551 }
552
Adrian Roos2fbf4d52016-10-20 14:40:51 -0700553 private void sendForegroundBroadcastToAllUsers(String action) {
554 getContext().sendBroadcastAsUser(new Intent(action)
555 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND), UserHandle.ALL);
556 }
557
Jeff Brown62c82e42012-09-26 01:30:41 -0700558 private void updateAfterBroadcastLocked(String action, int enableFlags, int disableFlags) {
559 // Launch a dock activity
560 String category = null;
561 if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(action)) {
562 // Only launch car home when car mode is enabled and the caller
563 // has asked us to switch to it.
keunyounga7710492015-09-23 11:33:58 -0700564 if (mEnableCarDockLaunch
Jeff Brown62c82e42012-09-26 01:30:41 -0700565 && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
566 category = Intent.CATEGORY_CAR_DOCK;
567 }
568 } else if (UiModeManager.ACTION_ENTER_DESK_MODE.equals(action)) {
569 // Only launch car home when desk mode is enabled and the caller
570 // has asked us to switch to it. Currently re-using the car
571 // mode flag since we don't have a formal API for "desk mode".
572 if (ENABLE_LAUNCH_DESK_DOCK_APP
573 && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
574 category = Intent.CATEGORY_DESK_DOCK;
575 }
576 } else {
577 // Launch the standard home app if requested.
578 if ((disableFlags & UiModeManager.DISABLE_CAR_MODE_GO_HOME) != 0) {
579 category = Intent.CATEGORY_HOME;
580 }
581 }
582
583 if (LOG) {
584 Slog.v(TAG, String.format(
585 "Handling broadcast result for action %s: enable=0x%08x, disable=0x%08x, "
586 + "category=%s",
587 action, enableFlags, disableFlags, category));
588 }
589
590 sendConfigurationAndStartDreamOrDockAppLocked(category);
591 }
592
593 private void sendConfigurationAndStartDreamOrDockAppLocked(String category) {
594 // Update the configuration but don't send it yet.
595 mHoldingConfiguration = false;
596 updateConfigurationLocked();
597
598 // Start the dock app, if there is one.
599 boolean dockAppStarted = false;
600 if (category != null) {
601 // Now we are going to be careful about switching the
602 // configuration and starting the activity -- we need to
603 // do this in a specific order under control of the
604 // activity manager, to do it cleanly. So compute the
605 // new config, but don't set it yet, and let the
606 // activity manager take care of both the start and config
607 // change.
608 Intent homeIntent = buildHomeIntent(category);
Adam Lesinski182f73f2013-12-05 16:48:06 -0800609 if (Sandman.shouldStartDockApp(getContext(), homeIntent)) {
Jeff Brown11159e92012-10-11 15:58:37 -0700610 try {
611 int result = ActivityManagerNative.getDefault().startActivityWithConfig(
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800612 null, null, homeIntent, null, null, null, 0, 0,
Jeff Brown11159e92012-10-11 15:58:37 -0700613 mConfiguration, null, UserHandle.USER_CURRENT);
614 if (result >= ActivityManager.START_SUCCESS) {
615 dockAppStarted = true;
616 } else if (result != ActivityManager.START_INTENT_NOT_RESOLVED) {
617 Slog.e(TAG, "Could not start dock app: " + homeIntent
618 + ", startActivityWithConfig result " + result);
619 }
620 } catch (RemoteException ex) {
621 Slog.e(TAG, "Could not start dock app: " + homeIntent, ex);
Jeff Brown62c82e42012-09-26 01:30:41 -0700622 }
Jeff Brown62c82e42012-09-26 01:30:41 -0700623 }
624 }
625
626 // Send the new configuration.
627 sendConfigurationLocked();
628
629 // If we did not start a dock app, then start dreaming if supported.
Jeff Brown11159e92012-10-11 15:58:37 -0700630 if (category != null && !dockAppStarted) {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800631 Sandman.startDreamWhenDockedIfAppropriate(getContext());
Jeff Brown62c82e42012-09-26 01:30:41 -0700632 }
633 }
634
Dianne Hackborn7299c412010-03-04 18:41:49 -0800635 private void adjustStatusBarCarModeLocked() {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800636 final Context context = getContext();
Dianne Hackborn7299c412010-03-04 18:41:49 -0800637 if (mStatusBarManager == null) {
Jeff Brown487bb6e2012-10-11 13:35:42 -0700638 mStatusBarManager = (StatusBarManager)
Adam Lesinski182f73f2013-12-05 16:48:06 -0800639 context.getSystemService(Context.STATUS_BAR_SERVICE);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800640 }
641
Joe Onorato089de882010-04-12 08:18:45 -0700642 // Fear not: StatusBarManagerService manages a list of requests to disable
Dianne Hackborn7299c412010-03-04 18:41:49 -0800643 // features of the status bar; these are ORed together to form the
644 // active disabled list. So if (for example) the device is locked and
645 // the status bar should be totally disabled, the calls below will
646 // have no effect until the device is unlocked.
647 if (mStatusBarManager != null) {
648 mStatusBarManager.disable(mCarModeEnabled
649 ? StatusBarManager.DISABLE_NOTIFICATION_TICKER
650 : StatusBarManager.DISABLE_NONE);
651 }
652
653 if (mNotificationManager == null) {
654 mNotificationManager = (NotificationManager)
Adam Lesinski182f73f2013-12-05 16:48:06 -0800655 context.getSystemService(Context.NOTIFICATION_SERVICE);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800656 }
657
658 if (mNotificationManager != null) {
659 if (mCarModeEnabled) {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800660 Intent carModeOffIntent = new Intent(context, DisableCarModeActivity.class);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800661
Chris Wren1ce4b6d2015-06-11 10:19:43 -0400662 Notification.Builder n = new Notification.Builder(context)
663 .setSmallIcon(R.drawable.stat_notify_car_mode)
664 .setDefaults(Notification.DEFAULT_LIGHTS)
665 .setOngoing(true)
666 .setWhen(0)
667 .setColor(context.getColor(
668 com.android.internal.R.color.system_notification_accent_color))
669 .setContentTitle(
670 context.getString(R.string.car_mode_disable_notification_title))
671 .setContentText(
672 context.getString(R.string.car_mode_disable_notification_message))
673 .setContentIntent(
674 PendingIntent.getActivityAsUser(context, 0, carModeOffIntent, 0,
675 null, UserHandle.CURRENT));
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700676 mNotificationManager.notifyAsUser(null,
Chris Wren1ce4b6d2015-06-11 10:19:43 -0400677 R.string.car_mode_disable_notification_title, n.build(), UserHandle.ALL);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800678 } else {
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700679 mNotificationManager.cancelAsUser(null,
680 R.string.car_mode_disable_notification_title, UserHandle.ALL);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800681 }
682 }
683 }
684
Jeff Brown2416e092012-08-21 22:12:20 -0700685 private void updateComputedNightModeLocked() {
Adam Lesinski05199e82015-03-19 14:37:11 -0700686 if (mTwilightManager != null) {
Justin Klaassen908b86c2016-08-08 09:18:42 -0700687 TwilightState state = mTwilightManager.getLastTwilightState();
Adam Lesinski05199e82015-03-19 14:37:11 -0700688 if (state != null) {
689 mComputedNightMode = state.isNight();
690 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800691 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800692 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100693
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100694
Dianne Hackborn7299c412010-03-04 18:41:49 -0800695}