blob: b1e2c0fe9586a6b4e02bb35d09fa86391f2593b6 [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
Tyler Gunndaef6682019-09-30 15:12:24 -070019import android.annotation.IntRange;
Justin Klaassen908b86c2016-08-08 09:18:42 -070020import android.annotation.Nullable;
Dianne Hackborn7299c412010-03-04 18:41:49 -080021import android.app.Activity;
Jeff Brown62c82e42012-09-26 01:30:41 -070022import android.app.ActivityManager;
Wale Ogunwale04d9cb52018-04-30 13:55:07 -070023import android.app.ActivityTaskManager;
Dianne Hackborn7299c412010-03-04 18:41:49 -080024import android.app.IUiModeManager;
25import android.app.Notification;
26import android.app.NotificationManager;
27import android.app.PendingIntent;
28import android.app.StatusBarManager;
29import android.app.UiModeManager;
Dianne Hackborn7299c412010-03-04 18:41:49 -080030import android.content.BroadcastReceiver;
31import android.content.Context;
32import android.content.Intent;
33import android.content.IntentFilter;
34import android.content.pm.PackageManager;
35import android.content.res.Configuration;
Alan Viverette4cc1e9e2015-02-12 11:01:06 -080036import android.content.res.Resources;
Salvador Martinezc500b272019-05-02 14:32:12 -070037import android.database.ContentObserver;
38import android.net.Uri;
Mike Lockwoode29db6a2010-03-05 13:45:51 -050039import android.os.BatteryManager;
Dianne Hackborn7299c412010-03-04 18:41:49 -080040import android.os.Binder;
Dianne Hackborn7299c412010-03-04 18:41:49 -080041import android.os.Handler;
Mike Lockwoode29db6a2010-03-05 13:45:51 -050042import android.os.PowerManager;
Kweku Adams4db6a3c2019-02-04 16:06:13 -080043import android.os.PowerManager.ServiceType;
44import android.os.PowerManagerInternal;
Tyler Gunndaef6682019-09-30 15:12:24 -070045import android.os.Process;
Dianne Hackborn7299c412010-03-04 18:41:49 -080046import android.os.RemoteException;
Alan Viveretteba0d98f2017-01-30 10:36:54 -050047import android.os.ResultReceiver;
Zak Cohen1a705732017-01-09 12:54:34 -080048import android.os.ServiceManager;
Alan Viveretteba0d98f2017-01-30 10:36:54 -050049import android.os.ShellCallback;
50import android.os.ShellCommand;
Beverly28e48fb2019-06-14 14:53:09 -040051import android.os.SystemProperties;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070052import android.os.UserHandle;
Salvador Martinezc500b272019-05-02 14:32:12 -070053import android.provider.Settings.Secure;
Jeff Brown11159e92012-10-11 15:58:37 -070054import android.service.dreams.Sandman;
Zak Cohen1a705732017-01-09 12:54:34 -080055import android.service.vr.IVrManager;
56import android.service.vr.IVrStateCallbacks;
Tyler Gunndaef6682019-09-30 15:12:24 -070057import android.util.ArraySet;
Dianne Hackborn7299c412010-03-04 18:41:49 -080058import android.util.Slog;
Dianne Hackborn7299c412010-03-04 18:41:49 -080059import com.android.internal.R;
Jay Aliomer8b2671b2019-10-24 13:18:06 -040060import com.android.internal.annotations.VisibleForTesting;
Dianne Hackborn7299c412010-03-04 18:41:49 -080061import com.android.internal.app.DisableCarModeActivity;
Chris Wren282cfef2017-03-27 15:01:44 -040062import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
Geoffrey Pitschaf759c52017-02-15 09:35:38 -050063import com.android.internal.notification.SystemNotificationChannels;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060064import com.android.internal.util.DumpUtils;
Adam Lesinski182f73f2013-12-05 16:48:06 -080065import com.android.server.twilight.TwilightListener;
66import com.android.server.twilight.TwilightManager;
67import com.android.server.twilight.TwilightState;
Jay Aliomer8b2671b2019-10-24 13:18:06 -040068import com.android.server.wm.WindowManagerInternal;
Dianne Hackborn7299c412010-03-04 18:41:49 -080069
Lucas Dupinb1f0c762018-09-18 10:33:38 -070070import java.io.FileDescriptor;
71import java.io.PrintWriter;
Tyler Gunndaef6682019-09-30 15:12:24 -070072import java.util.HashMap;
73import java.util.Map;
74import java.util.Set;
Lucas Dupinb1f0c762018-09-18 10:33:38 -070075
Jay Aliomer8b2671b2019-10-24 13:18:06 -040076import static android.content.Intent.ACTION_SCREEN_OFF;
77
Adam Lesinski182f73f2013-12-05 16:48:06 -080078final class UiModeManagerService extends SystemService {
Dianne Hackborn7299c412010-03-04 18:41:49 -080079 private static final String TAG = UiModeManager.class.getSimpleName();
80 private static final boolean LOG = false;
81
Daniel Sandler11ddf532011-11-16 11:10:03 -080082 // Enable launching of applications when entering the dock.
John Spurlock960779d2012-05-29 14:37:05 -040083 private static final boolean ENABLE_LAUNCH_DESK_DOCK_APP = true;
Beverly28e48fb2019-06-14 14:53:09 -040084 private static final String SYSTEM_PROPERTY_DEVICE_THEME = "persist.sys.theme";
Daniel Sandler11ddf532011-11-16 11:10:03 -080085
Dianne Hackborn7299c412010-03-04 18:41:49 -080086 final Object mLock = new Object();
Dianne Hackborn7299c412010-03-04 18:41:49 -080087 private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
Bernd Holzheyba9ab182010-03-12 09:30:29 +010088
Adam Lesinski182f73f2013-12-05 16:48:06 -080089 private int mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
Alan Viverette4cc1e9e2015-02-12 11:01:06 -080090 private int mNightMode = UiModeManager.MODE_NIGHT_NO;
Jay Aliomer8b2671b2019-10-24 13:18:06 -040091 // we use the override auto mode
92 // for example: force night mode off in the night time while in auto mode
93 private int mNightModeOverride = mNightMode;
94 protected static final String OVERRIDE_NIGHT_MODE = Secure.UI_NIGHT_MODE + "_override";
Adam Lesinski182f73f2013-12-05 16:48:06 -080095
Tyler Gunndaef6682019-09-30 15:12:24 -070096 private Map<Integer, String> mCarModePackagePriority = new HashMap<>();
Dianne Hackborn7299c412010-03-04 18:41:49 -080097 private boolean mCarModeEnabled = false;
Mike Lockwoode29db6a2010-03-05 13:45:51 -050098 private boolean mCharging = false;
Lucas Dupin53c6e292018-07-12 18:42:53 -070099 private boolean mPowerSave = false;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800100 private int mDefaultUiModeType;
101 private boolean mCarModeKeepsScreenOn;
102 private boolean mDeskModeKeepsScreenOn;
103 private boolean mTelevision;
John Spurlock6c191292014-04-03 16:37:27 -0400104 private boolean mWatch;
Zak Cohen1a705732017-01-09 12:54:34 -0800105 private boolean mVrHeadset;
Dianne Hackborn7299c412010-03-04 18:41:49 -0800106 private boolean mComputedNightMode;
keunyoung1d0a7cc2014-07-28 13:12:50 -0700107 private int mCarModeEnableFlags;
Salvador Martinezc500b272019-05-02 14:32:12 -0700108 private boolean mSetupWizardComplete;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800109
keunyounga7710492015-09-23 11:33:58 -0700110 // flag set by resource, whether to enable Car dock launch when starting car mode.
111 private boolean mEnableCarDockLaunch = true;
112 // flag set by resource, whether to lock UI mode to the default one or not.
113 private boolean mUiModeLocked = false;
114 // flag set by resource, whether to night mode change for normal all or not.
115 private boolean mNightModeLocked = false;
116
Adam Lesinski182f73f2013-12-05 16:48:06 -0800117 int mCurUiMode = 0;
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800118 private int mSetUiMode = 0;
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800119 private boolean mHoldingConfiguration = false;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800120
Dianne Hackborn7299c412010-03-04 18:41:49 -0800121 private Configuration mConfiguration = new Configuration();
Adam Lesinski182f73f2013-12-05 16:48:06 -0800122 boolean mSystemReady;
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100123
Adam Lesinski182f73f2013-12-05 16:48:06 -0800124 private final Handler mHandler = new Handler();
Dianne Hackborn7299c412010-03-04 18:41:49 -0800125
Adam Lesinski182f73f2013-12-05 16:48:06 -0800126 private TwilightManager mTwilightManager;
Dianne Hackborn7299c412010-03-04 18:41:49 -0800127 private NotificationManager mNotificationManager;
Dianne Hackborn7299c412010-03-04 18:41:49 -0800128 private StatusBarManager mStatusBarManager;
Jay Aliomer8b2671b2019-10-24 13:18:06 -0400129 private WindowManagerInternal mWindowManager;
Jeff Brown9fca9e92012-10-05 14:42:56 -0700130
Adam Lesinski182f73f2013-12-05 16:48:06 -0800131 private PowerManager.WakeLock mWakeLock;
Dianne Hackborn7299c412010-03-04 18:41:49 -0800132
Felipe Lemeff9ec382018-09-24 11:07:56 -0700133 private final LocalService mLocalService = new LocalService();
134
Jeff Brownb880d882014-02-10 19:47:07 -0800135 public UiModeManagerService(Context context) {
136 super(context);
137 }
138
Jay Aliomer8b2671b2019-10-24 13:18:06 -0400139 @VisibleForTesting
140 protected UiModeManagerService(Context context, WindowManagerInternal wm,
141 PowerManager.WakeLock wl, TwilightManager tm,
142 boolean setupWizardComplete) {
143 super(context);
144 mWindowManager = wm;
145 mWakeLock = wl;
146 mTwilightManager = tm;
147 mSetupWizardComplete = setupWizardComplete;
148 }
149
Adam Lesinski182f73f2013-12-05 16:48:06 -0800150 private static Intent buildHomeIntent(String category) {
Dianne Hackbornf5c5d222010-04-09 13:14:48 -0700151 Intent intent = new Intent(Intent.ACTION_MAIN);
152 intent.addCategory(category);
153 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
154 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
155 return intent;
156 }
John Spurlock960779d2012-05-29 14:37:05 -0400157
Dianne Hackborn7299c412010-03-04 18:41:49 -0800158 // The broadcast receiver which receives the result of the ordered broadcast sent when
159 // the dock state changes. The original ordered broadcast is sent with an initial result
160 // code of RESULT_OK. If any of the registered broadcast receivers changes this value, e.g.,
161 // to RESULT_CANCELED, then the intent to start a dock app will not be sent.
162 private final BroadcastReceiver mResultReceiver = new BroadcastReceiver() {
163 @Override
164 public void onReceive(Context context, Intent intent) {
165 if (getResultCode() != Activity.RESULT_OK) {
Daniel Sandler69a1da42011-11-04 15:08:30 -0400166 if (LOG) {
John Spurlock960779d2012-05-29 14:37:05 -0400167 Slog.v(TAG, "Handling broadcast result for action " + intent.getAction()
Daniel Sandler69a1da42011-11-04 15:08:30 -0400168 + ": canceled: " + getResultCode());
169 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800170 return;
171 }
172
Jeff Brown62c82e42012-09-26 01:30:41 -0700173 final int enableFlags = intent.getIntExtra("enableFlags", 0);
174 final int disableFlags = intent.getIntExtra("disableFlags", 0);
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800175 synchronized (mLock) {
Jeff Brown62c82e42012-09-26 01:30:41 -0700176 updateAfterBroadcastLocked(intent.getAction(), enableFlags, disableFlags);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800177 }
178 }
179 };
180
Dianne Hackborn7299c412010-03-04 18:41:49 -0800181 private final BroadcastReceiver mDockModeReceiver = new BroadcastReceiver() {
182 @Override
183 public void onReceive(Context context, Intent intent) {
184 int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
185 Intent.EXTRA_DOCK_STATE_UNDOCKED);
186 updateDockState(state);
187 }
188 };
189
Mike Lockwoode29db6a2010-03-05 13:45:51 -0500190 private final BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() {
191 @Override
192 public void onReceive(Context context, Intent intent) {
Lucas Dupin53c6e292018-07-12 18:42:53 -0700193 switch (intent.getAction()) {
194 case Intent.ACTION_BATTERY_CHANGED:
195 mCharging = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
196 break;
Lucas Dupin53c6e292018-07-12 18:42:53 -0700197 }
Mike Lockwoode29db6a2010-03-05 13:45:51 -0500198 synchronized (mLock) {
199 if (mSystemReady) {
Dianne Hackbornf5c5d222010-04-09 13:14:48 -0700200 updateLocked(0, 0);
Mike Lockwoode29db6a2010-03-05 13:45:51 -0500201 }
202 }
203 }
204 };
205
Adam Lesinski182f73f2013-12-05 16:48:06 -0800206 private final TwilightListener mTwilightListener = new TwilightListener() {
Dianne Hackborn57f45032010-06-17 15:49:33 -0700207 @Override
Justin Klaassen908b86c2016-08-08 09:18:42 -0700208 public void onTwilightStateChanged(@Nullable TwilightState state) {
209 synchronized (mLock) {
210 if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
Jay Aliomer8b2671b2019-10-24 13:18:06 -0400211 final IntentFilter intentFilter =
212 new IntentFilter(ACTION_SCREEN_OFF);
213 getContext().registerReceiver(mOnScreenOffHandler, intentFilter);
214 }
215 }
216 }
217 };
218
219 private final BroadcastReceiver mOnScreenOffHandler = new BroadcastReceiver() {
220 @Override
221 public void onReceive(Context context, Intent intent) {
222 synchronized (mLock) {
223 updateLocked(0, 0);
224 try {
225 getContext().unregisterReceiver(mOnScreenOffHandler);
226 } catch (IllegalArgumentException e) {
227 // we ignore this exception if the receiver is unregistered already.
Justin Klaassen908b86c2016-08-08 09:18:42 -0700228 }
229 }
Dianne Hackborn57f45032010-06-17 15:49:33 -0700230 }
231 };
232
Zak Cohen1a705732017-01-09 12:54:34 -0800233 private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
234 @Override
235 public void onVrStateChanged(boolean enabled) {
236 synchronized (mLock) {
237 mVrHeadset = enabled;
238 if (mSystemReady) {
239 updateLocked(0, 0);
240 }
241 }
242 }
243 };
244
Salvador Martinezc500b272019-05-02 14:32:12 -0700245 private final ContentObserver mSetupWizardObserver = new ContentObserver(mHandler) {
246 @Override
247 public void onChange(boolean selfChange, Uri uri) {
248 // setup wizard is done now so we can unblock
249 if (setupWizardCompleteForCurrentUser()) {
250 mSetupWizardComplete = true;
251 getContext().getContentResolver().unregisterContentObserver(mSetupWizardObserver);
252 // update night mode
253 Context context = getContext();
254 updateNightModeFromSettings(context, context.getResources(),
255 UserHandle.getCallingUserId());
256 updateLocked(0, 0);
257 }
258 }
259 };
260
Beverly4f2ff8e2019-07-22 17:15:58 -0400261 private final ContentObserver mDarkThemeObserver = new ContentObserver(mHandler) {
262 @Override
263 public void onChange(boolean selfChange, Uri uri) {
264 int mode = Secure.getIntForUser(getContext().getContentResolver(), Secure.UI_NIGHT_MODE,
265 mNightMode, 0);
Jay Aliomer8b2671b2019-10-24 13:18:06 -0400266 mode = mode == UiModeManager.MODE_NIGHT_AUTO
267 ? UiModeManager.MODE_NIGHT_YES : UiModeManager.MODE_NIGHT_NO;
Beverly4f2ff8e2019-07-22 17:15:58 -0400268 SystemProperties.set(SYSTEM_PROPERTY_DEVICE_THEME, Integer.toString(mode));
269 }
270 };
271
Salvador Martinezc500b272019-05-02 14:32:12 -0700272 @Override
273 public void onSwitchUser(int userHandle) {
274 super.onSwitchUser(userHandle);
275 getContext().getContentResolver().unregisterContentObserver(mSetupWizardObserver);
276 verifySetupWizardCompleted();
277 }
278
Adam Lesinski182f73f2013-12-05 16:48:06 -0800279 @Override
280 public void onStart() {
281 final Context context = getContext();
Alan Viverette4cc1e9e2015-02-12 11:01:06 -0800282
Adam Lesinski182f73f2013-12-05 16:48:06 -0800283 final PowerManager powerManager =
284 (PowerManager) context.getSystemService(Context.POWER_SERVICE);
285 mWakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
Jay Aliomer8b2671b2019-10-24 13:18:06 -0400286 mWindowManager = LocalServices.getService(WindowManagerInternal.class);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800287
Salvador Martinezc500b272019-05-02 14:32:12 -0700288 // If setup isn't complete for this user listen for completion so we can unblock
289 // being able to send a night mode configuration change event
290 verifySetupWizardCompleted();
291
Adam Lesinski182f73f2013-12-05 16:48:06 -0800292 context.registerReceiver(mDockModeReceiver,
Dianne Hackborn7299c412010-03-04 18:41:49 -0800293 new IntentFilter(Intent.ACTION_DOCK_EVENT));
Lucas Dupin53c6e292018-07-12 18:42:53 -0700294 IntentFilter batteryFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Lucas Dupin53c6e292018-07-12 18:42:53 -0700295 context.registerReceiver(mBatteryReceiver, batteryFilter);
Mike Lockwoode29db6a2010-03-05 13:45:51 -0500296
Kweku Adams4db6a3c2019-02-04 16:06:13 -0800297 PowerManagerInternal localPowerManager =
298 LocalServices.getService(PowerManagerInternal.class);
299 mPowerSave = localPowerManager.getLowPowerState(ServiceType.NIGHT_MODE).batterySaverEnabled;
300 localPowerManager.registerLowPowerModeObserver(ServiceType.NIGHT_MODE,
301 state -> {
302 synchronized (mLock) {
303 if (mPowerSave == state.batterySaverEnabled) {
304 return;
305 }
306 mPowerSave = state.batterySaverEnabled;
307 if (mSystemReady) {
308 updateLocked(0, 0);
309 }
310 }
311 });
312
Dianne Hackborn7299c412010-03-04 18:41:49 -0800313 mConfiguration.setToDefaults();
Mike Lockwoode29db6a2010-03-05 13:45:51 -0500314
Alan Viverette4cc1e9e2015-02-12 11:01:06 -0800315 final Resources res = context.getResources();
316 mDefaultUiModeType = res.getInteger(
Joe Onorato44fcb832011-12-14 20:59:30 -0800317 com.android.internal.R.integer.config_defaultUiModeType);
Alan Viverette4cc1e9e2015-02-12 11:01:06 -0800318 mCarModeKeepsScreenOn = (res.getInteger(
Mike Lockwoode29db6a2010-03-05 13:45:51 -0500319 com.android.internal.R.integer.config_carDockKeepsScreenOn) == 1);
Alan Viverette4cc1e9e2015-02-12 11:01:06 -0800320 mDeskModeKeepsScreenOn = (res.getInteger(
Mike Lockwoode29db6a2010-03-05 13:45:51 -0500321 com.android.internal.R.integer.config_deskDockKeepsScreenOn) == 1);
keunyounga7710492015-09-23 11:33:58 -0700322 mEnableCarDockLaunch = res.getBoolean(
323 com.android.internal.R.bool.config_enableCarDockHomeLaunch);
324 mUiModeLocked = res.getBoolean(com.android.internal.R.bool.config_lockUiMode);
325 mNightModeLocked = res.getBoolean(com.android.internal.R.bool.config_lockDayNightMode);
Dianne Hackborn0cf2c8a2012-05-17 17:29:49 -0700326
Alan Viverette4cc1e9e2015-02-12 11:01:06 -0800327 final PackageManager pm = context.getPackageManager();
328 mTelevision = pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION)
329 || pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
330 mWatch = pm.hasSystemFeature(PackageManager.FEATURE_WATCH);
331
Salvador Martinez2f792ef2018-09-26 17:33:51 -0700332 updateNightModeFromSettings(context, res, UserHandle.getCallingUserId());
Jeff Brown2416e092012-08-21 22:12:20 -0700333
Adam Lesinski05199e82015-03-19 14:37:11 -0700334 // Update the initial, static configurations.
Felipe Lemeb68b7692019-10-09 10:43:03 -0700335 SystemServerInitThreadPool.submit(() -> {
Fyodor Kupolove29a5a12016-12-16 16:14:17 -0800336 synchronized (mLock) {
337 updateConfigurationLocked();
338 sendConfigurationLocked();
339 }
Adam Lesinski182f73f2013-12-05 16:48:06 -0800340
Fyodor Kupolove29a5a12016-12-16 16:14:17 -0800341 }, TAG + ".onStart");
Adam Lesinski182f73f2013-12-05 16:48:06 -0800342 publishBinderService(Context.UI_MODE_SERVICE, mService);
Felipe Lemeff9ec382018-09-24 11:07:56 -0700343 publishLocalService(UiModeManagerInternal.class, mLocalService);
Salvador Martinez2f792ef2018-09-26 17:33:51 -0700344
345 IntentFilter filter = new IntentFilter();
346 filter.addAction(Intent.ACTION_USER_SWITCHED);
347 context.registerReceiver(new UserSwitchedReceiver(), filter, null, mHandler);
Beverly4f2ff8e2019-07-22 17:15:58 -0400348
349 context.getContentResolver().registerContentObserver(Secure.getUriFor(Secure.UI_NIGHT_MODE),
350 false, mDarkThemeObserver, 0);
Salvador Martinez2f792ef2018-09-26 17:33:51 -0700351 }
352
Jay Aliomer8b2671b2019-10-24 13:18:06 -0400353 @VisibleForTesting
354 protected IUiModeManager getService() {
355 return mService;
356 }
357
358 @VisibleForTesting
359 protected Configuration getConfiguration() {
360 return mConfiguration;
361 }
362
Salvador Martinezc500b272019-05-02 14:32:12 -0700363 // Records whether setup wizard has happened or not and adds an observer for this user if not.
364 private void verifySetupWizardCompleted() {
365 final Context context = getContext();
366 final int userId = UserHandle.getCallingUserId();
367 if (!setupWizardCompleteForCurrentUser()) {
368 mSetupWizardComplete = false;
369 context.getContentResolver().registerContentObserver(
370 Secure.getUriFor(
371 Secure.USER_SETUP_COMPLETE), false, mSetupWizardObserver, userId);
372 } else {
373 mSetupWizardComplete = true;
374 }
375 }
376
377 private boolean setupWizardCompleteForCurrentUser() {
378 return Secure.getIntForUser(getContext().getContentResolver(),
379 Secure.USER_SETUP_COMPLETE, 0, UserHandle.getCallingUserId()) == 1;
380 }
381
Salvador Martinez2f792ef2018-09-26 17:33:51 -0700382 /**
383 * Updates the night mode setting in Settings.Global and returns if the value was successfully
384 * changed.
385 * @param context A valid context
386 * @param res A valid resource object
387 * @param userId The user to update the setting for
388 * @return True if the new value is different from the old value. False otherwise.
389 */
390 private boolean updateNightModeFromSettings(Context context, Resources res, int userId) {
391 final int defaultNightMode = res.getInteger(
392 com.android.internal.R.integer.config_defaultNightMode);
393 int oldNightMode = mNightMode;
Salvador Martinezc500b272019-05-02 14:32:12 -0700394 if (mSetupWizardComplete) {
395 mNightMode = Secure.getIntForUser(context.getContentResolver(),
396 Secure.UI_NIGHT_MODE, defaultNightMode, userId);
Jay Aliomer8b2671b2019-10-24 13:18:06 -0400397 mNightModeOverride = Secure.getIntForUser(context.getContentResolver(),
398 OVERRIDE_NIGHT_MODE, defaultNightMode, userId);
Salvador Martinezc500b272019-05-02 14:32:12 -0700399 } else {
400 mNightMode = defaultNightMode;
Jay Aliomer8b2671b2019-10-24 13:18:06 -0400401 mNightModeOverride = defaultNightMode;
Salvador Martinezc500b272019-05-02 14:32:12 -0700402 }
Salvador Martinez2f792ef2018-09-26 17:33:51 -0700403
Beverly28e48fb2019-06-14 14:53:09 -0400404 return oldNightMode != mNightMode;
Dianne Hackborn7299c412010-03-04 18:41:49 -0800405 }
406
Alan Viveretteba0d98f2017-01-30 10:36:54 -0500407 private final IUiModeManager.Stub mService = new IUiModeManager.Stub() {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800408 @Override
Tyler Gunndaef6682019-09-30 15:12:24 -0700409 public void enableCarMode(@UiModeManager.EnableCarMode int flags,
410 @IntRange(from = 0) int priority, String callingPackage) {
keunyounga7710492015-09-23 11:33:58 -0700411 if (isUiModeLocked()) {
412 Slog.e(TAG, "enableCarMode while UI mode is locked");
413 return;
414 }
Tyler Gunndaef6682019-09-30 15:12:24 -0700415
416 if (priority != UiModeManager.DEFAULT_PRIORITY
417 && getContext().checkCallingOrSelfPermission(
418 android.Manifest.permission.ENTER_CAR_MODE_PRIORITIZED)
419 != PackageManager.PERMISSION_GRANTED) {
420 throw new SecurityException("Enabling car mode with a priority requires "
421 + "permission ENTER_CAR_MODE_PRIORITIZED");
422 }
423
Adam Lesinski182f73f2013-12-05 16:48:06 -0800424 final long ident = Binder.clearCallingIdentity();
425 try {
426 synchronized (mLock) {
Tyler Gunndaef6682019-09-30 15:12:24 -0700427 setCarModeLocked(true, flags, priority, callingPackage);
Adam Lesinski182f73f2013-12-05 16:48:06 -0800428 if (mSystemReady) {
429 updateLocked(flags, 0);
430 }
Jeff Brown487bb6e2012-10-11 13:35:42 -0700431 }
Adam Lesinski182f73f2013-12-05 16:48:06 -0800432 } finally {
433 Binder.restoreCallingIdentity(ident);
Mike Lockwood924e1642010-03-05 11:56:53 -0500434 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800435 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800436
Tyler Gunndaef6682019-09-30 15:12:24 -0700437 /**
438 * This method is only kept around for the time being; the AIDL has an UnsupportedAppUsage
439 * tag which means this method is technically considered part of the greylist "API".
440 * @param flags
441 */
Adam Lesinski182f73f2013-12-05 16:48:06 -0800442 @Override
Tyler Gunndaef6682019-09-30 15:12:24 -0700443 public void disableCarMode(@UiModeManager.DisableCarMode int flags) {
444 disableCarModeByCallingPackage(flags, null /* callingPackage */);
445 }
446
447 /**
448 * Handles requests to disable car mode.
449 * @param flags Disable car mode flags
450 * @param callingPackage
451 */
452 @Override
453 public void disableCarModeByCallingPackage(@UiModeManager.DisableCarMode int flags,
454 String callingPackage) {
keunyounga7710492015-09-23 11:33:58 -0700455 if (isUiModeLocked()) {
456 Slog.e(TAG, "disableCarMode while UI mode is locked");
457 return;
458 }
Tyler Gunndaef6682019-09-30 15:12:24 -0700459
460 // If the caller is the system, we will allow the DISABLE_CAR_MODE_ALL_PRIORITIES car
461 // mode flag to be specified; this is so that the user can disable car mode at all
462 // priorities using the persistent notification.
463 boolean isSystemCaller = Binder.getCallingUid() == Process.SYSTEM_UID;
464 final int carModeFlags =
465 isSystemCaller ? flags : flags & ~UiModeManager.DISABLE_CAR_MODE_ALL_PRIORITIES;
466
Adam Lesinski182f73f2013-12-05 16:48:06 -0800467 final long ident = Binder.clearCallingIdentity();
468 try {
469 synchronized (mLock) {
Tyler Gunndaef6682019-09-30 15:12:24 -0700470 // Determine if the caller has enabled car mode at a priority other than the
471 // default one. If they have, then attempt to disable at that priority.
472 int priority = mCarModePackagePriority.entrySet()
473 .stream()
474 .filter(e -> e.getValue().equals(callingPackage))
475 .findFirst()
476 .map(Map.Entry::getKey)
477 .orElse(UiModeManager.DEFAULT_PRIORITY);
478
479 setCarModeLocked(false, carModeFlags, priority, callingPackage);
Adam Lesinski182f73f2013-12-05 16:48:06 -0800480 if (mSystemReady) {
481 updateLocked(0, flags);
482 }
Jeff Brown487bb6e2012-10-11 13:35:42 -0700483 }
Adam Lesinski182f73f2013-12-05 16:48:06 -0800484 } finally {
485 Binder.restoreCallingIdentity(ident);
Mike Lockwood924e1642010-03-05 11:56:53 -0500486 }
Jeff Brown487bb6e2012-10-11 13:35:42 -0700487 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100488
Adam Lesinski182f73f2013-12-05 16:48:06 -0800489 @Override
490 public int getCurrentModeType() {
491 final long ident = Binder.clearCallingIdentity();
492 try {
493 synchronized (mLock) {
494 return mCurUiMode & Configuration.UI_MODE_TYPE_MASK;
Jeff Brown487bb6e2012-10-11 13:35:42 -0700495 }
Adam Lesinski182f73f2013-12-05 16:48:06 -0800496 } finally {
497 Binder.restoreCallingIdentity(ident);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800498 }
499 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100500
Adam Lesinski182f73f2013-12-05 16:48:06 -0800501 @Override
502 public void setNightMode(int mode) {
Lucas Dupinc5aaf452018-09-20 16:10:07 -0700503 if (isNightModeLocked() && (getContext().checkCallingOrSelfPermission(
keunyounga7710492015-09-23 11:33:58 -0700504 android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)
505 != PackageManager.PERMISSION_GRANTED)) {
Lucas Dupinc5aaf452018-09-20 16:10:07 -0700506 Slog.e(TAG, "Night mode locked, requires MODIFY_DAY_NIGHT_MODE permission");
keunyounga7710492015-09-23 11:33:58 -0700507 return;
508 }
Salvador Martinezc500b272019-05-02 14:32:12 -0700509 if (!mSetupWizardComplete) {
510 Slog.d(TAG, "Night mode cannot be changed before setup wizard completes.");
511 return;
512 }
Adam Lesinski182f73f2013-12-05 16:48:06 -0800513 switch (mode) {
514 case UiModeManager.MODE_NIGHT_NO:
515 case UiModeManager.MODE_NIGHT_YES:
516 case UiModeManager.MODE_NIGHT_AUTO:
517 break;
518 default:
519 throw new IllegalArgumentException("Unknown mode: " + mode);
520 }
521
Salvador Martinez2f792ef2018-09-26 17:33:51 -0700522 final int user = UserHandle.getCallingUserId();
Adam Lesinski182f73f2013-12-05 16:48:06 -0800523 final long ident = Binder.clearCallingIdentity();
524 try {
525 synchronized (mLock) {
Alan Viverette4cc1e9e2015-02-12 11:01:06 -0800526 if (mNightMode != mode) {
Jay Aliomer8b2671b2019-10-24 13:18:06 -0400527 if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
528 try {
529 getContext().unregisterReceiver(mOnScreenOffHandler);
530 } catch (IllegalArgumentException e) {
531 // we ignore this exception if the receiver is unregistered already.
532 }
533 }
Winson3f5ad732019-03-04 15:21:04 -0800534 // Only persist setting if not in car mode
535 if (!mCarModeEnabled) {
Salvador Martinezc500b272019-05-02 14:32:12 -0700536 Secure.putIntForUser(getContext().getContentResolver(),
537 Secure.UI_NIGHT_MODE, mode, user);
Jay Aliomer8b2671b2019-10-24 13:18:06 -0400538 Secure.putIntForUser(getContext().getContentResolver(),
539 OVERRIDE_NIGHT_MODE, mNightModeOverride, user);
Winsonadc69672019-01-28 14:56:12 -0800540 }
541
Adam Lesinski182f73f2013-12-05 16:48:06 -0800542 mNightMode = mode;
Jay Aliomer8b2671b2019-10-24 13:18:06 -0400543 mNightModeOverride = mode;
544 //on screen off will update configuration instead
545 if (mNightMode != UiModeManager.MODE_NIGHT_AUTO) {
546 updateLocked(0, 0);
547 } else {
548 getContext().registerReceiver(
549 mOnScreenOffHandler, new IntentFilter(ACTION_SCREEN_OFF));
550 }
Adam Lesinski182f73f2013-12-05 16:48:06 -0800551 }
552 }
553 } finally {
554 Binder.restoreCallingIdentity(ident);
555 }
556 }
557
558 @Override
559 public int getNightMode() {
560 synchronized (mLock) {
561 return mNightMode;
562 }
563 }
564
565 @Override
keunyounga7710492015-09-23 11:33:58 -0700566 public boolean isUiModeLocked() {
567 synchronized (mLock) {
568 return mUiModeLocked;
569 }
570 }
571
572 @Override
573 public boolean isNightModeLocked() {
574 synchronized (mLock) {
575 return mNightModeLocked;
576 }
577 }
578
579 @Override
Alan Viveretteba0d98f2017-01-30 10:36:54 -0500580 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
581 String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
582 new Shell(mService).exec(mService, in, out, err, args, callback, resultReceiver);
583 }
584
585 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -0800586 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600587 if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800588 dumpImpl(pw);
589 }
Jay Aliomer8b2671b2019-10-24 13:18:06 -0400590
591 @Override
592 public boolean setNightModeActivated(boolean active) {
593 synchronized (mLock) {
594 final long ident = Binder.clearCallingIdentity();
595 try {
596 if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
597 try {
598 getContext().unregisterReceiver(mOnScreenOffHandler);
599 } catch (IllegalArgumentException e) {
600 }
601 mNightModeOverride = active
602 ? UiModeManager.MODE_NIGHT_YES : UiModeManager.MODE_NIGHT_NO;
603 } else if (mNightMode == UiModeManager.MODE_NIGHT_NO
604 && active) {
605 mNightMode = UiModeManager.MODE_NIGHT_YES;
606 } else if (mNightMode == UiModeManager.MODE_NIGHT_YES
607 && !active) {
608 mNightMode = UiModeManager.MODE_NIGHT_NO;
609 }
610 updateConfigurationLocked();
611 sendConfigurationLocked();
612 return true;
613 } finally {
614 Binder.restoreCallingIdentity(ident);
615 }
616 }
617 }
Adam Lesinski182f73f2013-12-05 16:48:06 -0800618 };
619
620 void dumpImpl(PrintWriter pw) {
Jeff Brown487bb6e2012-10-11 13:35:42 -0700621 synchronized (mLock) {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800622 pw.println("Current UI Mode Service state:");
623 pw.print(" mDockState="); pw.print(mDockState);
Tyler Gunndaef6682019-09-30 15:12:24 -0700624 pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState);
625
Felipe Lemeff9ec382018-09-24 11:07:56 -0700626 pw.print(" mNightMode="); pw.print(mNightMode); pw.print(" (");
Tyler Gunndaef6682019-09-30 15:12:24 -0700627 pw.print(Shell.nightModeToStr(mNightMode)); pw.print(") ");
628 pw.print(" mNightModeLocked="); pw.println(mNightModeLocked);
629
630 pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled);
631 pw.print(" (carModeApps=");
632 for (Map.Entry<Integer, String> entry : mCarModePackagePriority.entrySet()) {
633 pw.print(entry.getKey());
634 pw.print(":");
635 pw.print(entry.getValue());
636 pw.print(" ");
637 }
638 pw.println("");
639 pw.print(" mComputedNightMode="); pw.print(mComputedNightMode);
640 pw.print(" mCarModeEnableFlags="); pw.print(mCarModeEnableFlags);
641 pw.print(" mEnableCarDockLaunch="); pw.println(mEnableCarDockLaunch);
642
Adam Lesinski182f73f2013-12-05 16:48:06 -0800643 pw.print(" mCurUiMode=0x"); pw.print(Integer.toHexString(mCurUiMode));
Tyler Gunndaef6682019-09-30 15:12:24 -0700644 pw.print(" mUiModeLocked="); pw.print(mUiModeLocked);
645 pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode));
646
Adam Lesinski182f73f2013-12-05 16:48:06 -0800647 pw.print(" mHoldingConfiguration="); pw.print(mHoldingConfiguration);
Tyler Gunndaef6682019-09-30 15:12:24 -0700648 pw.print(" mSystemReady="); pw.println(mSystemReady);
649
Adam Lesinski05199e82015-03-19 14:37:11 -0700650 if (mTwilightManager != null) {
651 // We may not have a TwilightManager.
Justin Klaassen908b86c2016-08-08 09:18:42 -0700652 pw.print(" mTwilightService.getLastTwilightState()=");
653 pw.println(mTwilightManager.getLastTwilightState());
Adam Lesinski05199e82015-03-19 14:37:11 -0700654 }
Jeff Brown487bb6e2012-10-11 13:35:42 -0700655 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800656 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100657
Adam Lesinski182f73f2013-12-05 16:48:06 -0800658 @Override
659 public void onBootPhase(int phase) {
660 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
661 synchronized (mLock) {
Adam Lesinski05199e82015-03-19 14:37:11 -0700662 mTwilightManager = getLocalService(TwilightManager.class);
Adam Lesinski182f73f2013-12-05 16:48:06 -0800663 mSystemReady = true;
664 mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR;
665 updateComputedNightModeLocked();
Zak Cohen1a705732017-01-09 12:54:34 -0800666 registerVrStateListener();
Adam Lesinski182f73f2013-12-05 16:48:06 -0800667 updateLocked(0, 0);
668 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800669 }
670 }
671
Tyler Gunndaef6682019-09-30 15:12:24 -0700672 /**
673 * Updates the global car mode state.
674 * The device is considered to be in car mode if there exists an app at any priority level which
675 * has entered car mode.
676 *
677 * @param enabled {@code true} if the caller wishes to enable car mode, {@code false} otherwise.
678 * @param flags Flags used when enabling/disabling car mode.
679 * @param priority The priority level for entering or exiting car mode; defaults to
680 * {@link UiModeManager#DEFAULT_PRIORITY} for callers using
681 * {@link UiModeManager#enableCarMode(int)}. Callers using
682 * {@link UiModeManager#enableCarMode(int, int)} may specify a priority.
683 * @param packageName The package name of the app which initiated the request to enable or
684 * disable car mode.
685 */
686 void setCarModeLocked(boolean enabled, int flags, int priority, String packageName) {
687 if (enabled) {
688 enableCarMode(priority, packageName);
689 } else {
690 disableCarMode(flags, priority, packageName);
691 }
692 boolean isCarModeNowEnabled = isCarModeEnabled();
Winsonadc69672019-01-28 14:56:12 -0800693
Tyler Gunndaef6682019-09-30 15:12:24 -0700694 if (mCarModeEnabled != isCarModeNowEnabled) {
695 mCarModeEnabled = isCarModeNowEnabled;
Winson3f5ad732019-03-04 15:21:04 -0800696 // When exiting car mode, restore night mode from settings
Tyler Gunndaef6682019-09-30 15:12:24 -0700697 if (!isCarModeNowEnabled) {
Winsonadc69672019-01-28 14:56:12 -0800698 Context context = getContext();
699 updateNightModeFromSettings(context,
700 context.getResources(),
701 UserHandle.getCallingUserId());
702 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800703 }
keunyoung1d0a7cc2014-07-28 13:12:50 -0700704 mCarModeEnableFlags = flags;
Dianne Hackborn7299c412010-03-04 18:41:49 -0800705 }
706
Tyler Gunndaef6682019-09-30 15:12:24 -0700707 /**
708 * Handles disabling car mode.
709 * <p>
710 * Car mode can be disabled at a priority level if any of the following is true:
711 * 1. The priority being disabled is the {@link UiModeManager#DEFAULT_PRIORITY}.
712 * 2. The priority level is enabled and the caller is the app who originally enabled it.
713 * 3. The {@link UiModeManager#DISABLE_CAR_MODE_ALL_PRIORITIES} flag was specified, meaning all
714 * car mode priorities are disabled.
715 *
716 * @param flags Car mode flags.
717 * @param priority The priority level at which to disable car mode.
718 * @param packageName The calling package which initiated the request.
719 */
720 private void disableCarMode(int flags, int priority, String packageName) {
721 boolean isDisableAll = (flags & UiModeManager.DISABLE_CAR_MODE_ALL_PRIORITIES) != 0;
722 boolean isPriorityTracked = mCarModePackagePriority.keySet().contains(priority);
723 boolean isDefaultPriority = priority == UiModeManager.DEFAULT_PRIORITY;
724 boolean isChangeAllowed =
725 // Anyone can disable the default priority.
726 isDefaultPriority
727 // If priority was enabled, only enabling package can disable it.
728 || isPriorityTracked && mCarModePackagePriority.get(priority).equals(packageName)
729 // Disable all priorities flag can disable all regardless.
730 || isDisableAll;
731 if (isChangeAllowed) {
732 Slog.d(TAG, "disableCarMode: disabling, priority=" + priority
733 + ", packageName=" + packageName);
734 if (isDisableAll) {
735 Set<Map.Entry<Integer, String>> entries =
736 new ArraySet<>(mCarModePackagePriority.entrySet());
737 mCarModePackagePriority.clear();
738
739 for (Map.Entry<Integer, String> entry : entries) {
740 notifyCarModeDisabled(entry.getKey(), entry.getValue());
741 }
742 } else {
743 mCarModePackagePriority.remove(priority);
744 notifyCarModeDisabled(priority, packageName);
745 }
746 }
747 }
748
749 /**
750 * Handles enabling car mode.
751 * <p>
752 * Car mode can be enabled at any priority if it has not already been enabled at that priority.
753 * The calling package is tracked for the first app which enters priority at the
754 * {@link UiModeManager#DEFAULT_PRIORITY}, though any app can disable it at that priority.
755 *
756 * @param priority The priority for enabling car mode.
757 * @param packageName The calling package which initiated the request.
758 */
759 private void enableCarMode(int priority, String packageName) {
760 boolean isPriorityTracked = mCarModePackagePriority.containsKey(priority);
761 boolean isPackagePresent = mCarModePackagePriority.containsValue(packageName);
762 if (!isPriorityTracked && !isPackagePresent) {
763 Slog.d(TAG, "enableCarMode: enabled at priority=" + priority + ", packageName="
764 + packageName);
765 mCarModePackagePriority.put(priority, packageName);
766 notifyCarModeEnabled(priority, packageName);
767 } else {
768 Slog.d(TAG, "enableCarMode: car mode at priority " + priority + " already enabled.");
769 }
770
771 }
772
773 private void notifyCarModeEnabled(int priority, String packageName) {
774 Intent intent = new Intent(UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED);
775 intent.putExtra(UiModeManager.EXTRA_CALLING_PACKAGE, packageName);
776 intent.putExtra(UiModeManager.EXTRA_PRIORITY, priority);
777 getContext().sendBroadcastAsUser(intent, UserHandle.ALL,
778 android.Manifest.permission.HANDLE_CAR_MODE_CHANGES);
779 }
780
781 private void notifyCarModeDisabled(int priority, String packageName) {
782 Intent intent = new Intent(UiModeManager.ACTION_EXIT_CAR_MODE_PRIORITIZED);
783 intent.putExtra(UiModeManager.EXTRA_CALLING_PACKAGE, packageName);
784 intent.putExtra(UiModeManager.EXTRA_PRIORITY, priority);
785 getContext().sendBroadcastAsUser(intent, UserHandle.ALL,
786 android.Manifest.permission.HANDLE_CAR_MODE_CHANGES);
787 }
788
789 /**
790 * Determines if car mode is enabled at any priority level.
791 * @return {@code true} if car mode is enabled, {@code false} otherwise.
792 */
793 private boolean isCarModeEnabled() {
794 return mCarModePackagePriority.size() > 0;
795 }
796
Jeff Brown487bb6e2012-10-11 13:35:42 -0700797 private void updateDockState(int newState) {
Dianne Hackborn7299c412010-03-04 18:41:49 -0800798 synchronized (mLock) {
799 if (newState != mDockState) {
800 mDockState = newState;
Tyler Gunndaef6682019-09-30 15:12:24 -0700801 setCarModeLocked(mDockState == Intent.EXTRA_DOCK_STATE_CAR, 0,
802 UiModeManager.DEFAULT_PRIORITY, "" /* packageName */);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800803 if (mSystemReady) {
Dianne Hackbornf5c5d222010-04-09 13:14:48 -0700804 updateLocked(UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME, 0);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800805 }
806 }
807 }
808 }
Mike Lockwoode29db6a2010-03-05 13:45:51 -0500809
Jeff Brown487bb6e2012-10-11 13:35:42 -0700810 private static boolean isDeskDockState(int state) {
Daniel Sandler69a1da42011-11-04 15:08:30 -0400811 switch (state) {
812 case Intent.EXTRA_DOCK_STATE_DESK:
813 case Intent.EXTRA_DOCK_STATE_LE_DESK:
814 case Intent.EXTRA_DOCK_STATE_HE_DESK:
815 return true;
816 default:
817 return false;
818 }
819 }
820
Jeff Brown487bb6e2012-10-11 13:35:42 -0700821 private void updateConfigurationLocked() {
John Spurlock6c191292014-04-03 16:37:27 -0400822 int uiMode = mDefaultUiModeType;
keunyounga7710492015-09-23 11:33:58 -0700823 if (mUiModeLocked) {
824 // no-op, keeps default one
825 } else if (mTelevision) {
John Spurlock6c191292014-04-03 16:37:27 -0400826 uiMode = Configuration.UI_MODE_TYPE_TELEVISION;
827 } else if (mWatch) {
828 uiMode = Configuration.UI_MODE_TYPE_WATCH;
829 } else if (mCarModeEnabled) {
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800830 uiMode = Configuration.UI_MODE_TYPE_CAR;
Daniel Sandler69a1da42011-11-04 15:08:30 -0400831 } else if (isDeskDockState(mDockState)) {
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800832 uiMode = Configuration.UI_MODE_TYPE_DESK;
Zak Cohen1a705732017-01-09 12:54:34 -0800833 } else if (mVrHeadset) {
834 uiMode = Configuration.UI_MODE_TYPE_VR_HEADSET;
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800835 }
Alan Viverette4cc1e9e2015-02-12 11:01:06 -0800836
837 if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
Justin Klaassen908b86c2016-08-08 09:18:42 -0700838 if (mTwilightManager != null) {
839 mTwilightManager.registerListener(mTwilightListener, mHandler);
840 }
Alan Viverette4cc1e9e2015-02-12 11:01:06 -0800841 updateComputedNightModeLocked();
842 uiMode |= mComputedNightMode ? Configuration.UI_MODE_NIGHT_YES
843 : Configuration.UI_MODE_NIGHT_NO;
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800844 } else {
Justin Klaassen908b86c2016-08-08 09:18:42 -0700845 if (mTwilightManager != null) {
846 mTwilightManager.unregisterListener(mTwilightListener);
847 }
Alan Viverette4cc1e9e2015-02-12 11:01:06 -0800848 uiMode |= mNightMode << 4;
Daniel Sandler8daf2a42010-04-02 10:15:09 -0400849 }
850
Winson3f5ad732019-03-04 15:21:04 -0800851 // Override night mode in power save mode if not in car mode
852 if (mPowerSave && !mCarModeEnabled) {
Lucas Dupin53c6e292018-07-12 18:42:53 -0700853 uiMode &= ~Configuration.UI_MODE_NIGHT_NO;
854 uiMode |= Configuration.UI_MODE_NIGHT_YES;
855 }
856
Daniel Sandler8daf2a42010-04-02 10:15:09 -0400857 if (LOG) {
John Spurlock960779d2012-05-29 14:37:05 -0400858 Slog.d(TAG,
859 "updateConfigurationLocked: mDockState=" + mDockState
Daniel Sandler8daf2a42010-04-02 10:15:09 -0400860 + "; mCarMode=" + mCarModeEnabled
861 + "; mNightMode=" + mNightMode
862 + "; uiMode=" + uiMode);
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800863 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100864
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800865 mCurUiMode = uiMode;
Jeff Brown62c82e42012-09-26 01:30:41 -0700866 if (!mHoldingConfiguration) {
Dianne Hackborn2ccda4d2010-03-22 21:49:15 -0700867 mConfiguration.uiMode = uiMode;
Jeff Brown62c82e42012-09-26 01:30:41 -0700868 }
869 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100870
Jeff Brown487bb6e2012-10-11 13:35:42 -0700871 private void sendConfigurationLocked() {
Jeff Brown62c82e42012-09-26 01:30:41 -0700872 if (mSetUiMode != mConfiguration.uiMode) {
873 mSetUiMode = mConfiguration.uiMode;
Jay Aliomerb45934a2019-12-09 14:45:09 -0500874 // load splash screen instead of screenshot
875 mWindowManager.clearSnapshotCache();
Jeff Brown62c82e42012-09-26 01:30:41 -0700876 try {
Wale Ogunwale04d9cb52018-04-30 13:55:07 -0700877 ActivityTaskManager.getService().updateConfiguration(mConfiguration);
Jeff Brown62c82e42012-09-26 01:30:41 -0700878 } catch (RemoteException e) {
879 Slog.w(TAG, "Failure communicating with activity manager", e);
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800880 }
881 }
882 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100883
Adam Lesinski182f73f2013-12-05 16:48:06 -0800884 void updateLocked(int enableFlags, int disableFlags) {
Jeff Brown487bb6e2012-10-11 13:35:42 -0700885 String action = null;
886 String oldAction = null;
887 if (mLastBroadcastState == Intent.EXTRA_DOCK_STATE_CAR) {
888 adjustStatusBarCarModeLocked();
889 oldAction = UiModeManager.ACTION_EXIT_CAR_MODE;
890 } else if (isDeskDockState(mLastBroadcastState)) {
891 oldAction = UiModeManager.ACTION_EXIT_DESK_MODE;
892 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100893
Jeff Brown487bb6e2012-10-11 13:35:42 -0700894 if (mCarModeEnabled) {
895 if (mLastBroadcastState != Intent.EXTRA_DOCK_STATE_CAR) {
Tobias Haamel780b2602010-03-15 12:54:45 +0100896 adjustStatusBarCarModeLocked();
Jeff Brown487bb6e2012-10-11 13:35:42 -0700897 if (oldAction != null) {
Adrian Roos2fbf4d52016-10-20 14:40:51 -0700898 sendForegroundBroadcastToAllUsers(oldAction);
Jeff Brown487bb6e2012-10-11 13:35:42 -0700899 }
900 mLastBroadcastState = Intent.EXTRA_DOCK_STATE_CAR;
901 action = UiModeManager.ACTION_ENTER_CAR_MODE;
902 }
903 } else if (isDeskDockState(mDockState)) {
904 if (!isDeskDockState(mLastBroadcastState)) {
905 if (oldAction != null) {
Adrian Roos2fbf4d52016-10-20 14:40:51 -0700906 sendForegroundBroadcastToAllUsers(oldAction);
Jeff Brown487bb6e2012-10-11 13:35:42 -0700907 }
908 mLastBroadcastState = mDockState;
909 action = UiModeManager.ACTION_ENTER_DESK_MODE;
910 }
911 } else {
912 mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
913 action = oldAction;
914 }
915
916 if (action != null) {
917 if (LOG) {
918 Slog.v(TAG, String.format(
919 "updateLocked: preparing broadcast: action=%s enable=0x%08x disable=0x%08x",
920 action, enableFlags, disableFlags));
Dianne Hackborn7299c412010-03-04 18:41:49 -0800921 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100922
Jeff Brown487bb6e2012-10-11 13:35:42 -0700923 // Send the ordered broadcast; the result receiver will receive after all
924 // broadcasts have been sent. If any broadcast receiver changes the result
925 // code from the initial value of RESULT_OK, then the result receiver will
926 // not launch the corresponding dock application. This gives apps a chance
927 // to override the behavior and stay in their app even when the device is
928 // placed into a dock.
929 Intent intent = new Intent(action);
930 intent.putExtra("enableFlags", enableFlags);
931 intent.putExtra("disableFlags", disableFlags);
Adrian Roos2fbf4d52016-10-20 14:40:51 -0700932 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Adam Lesinski182f73f2013-12-05 16:48:06 -0800933 getContext().sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
Jeff Brown487bb6e2012-10-11 13:35:42 -0700934 mResultReceiver, null, Activity.RESULT_OK, null, null);
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100935
Jeff Brown487bb6e2012-10-11 13:35:42 -0700936 // Attempting to make this transition a little more clean, we are going
937 // to hold off on doing a configuration change until we have finished
938 // the broadcast and started the home activity.
939 mHoldingConfiguration = true;
940 updateConfigurationLocked();
941 } else {
942 String category = null;
943 if (mCarModeEnabled) {
keunyounga7710492015-09-23 11:33:58 -0700944 if (mEnableCarDockLaunch
Jeff Brown487bb6e2012-10-11 13:35:42 -0700945 && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
946 category = Intent.CATEGORY_CAR_DOCK;
Dianne Hackborn7299c412010-03-04 18:41:49 -0800947 }
Daniel Sandler69a1da42011-11-04 15:08:30 -0400948 } else if (isDeskDockState(mDockState)) {
Jeff Brown487bb6e2012-10-11 13:35:42 -0700949 if (ENABLE_LAUNCH_DESK_DOCK_APP
950 && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
951 category = Intent.CATEGORY_DESK_DOCK;
Dianne Hackborn7299c412010-03-04 18:41:49 -0800952 }
953 } else {
Jeff Brown487bb6e2012-10-11 13:35:42 -0700954 if ((disableFlags & UiModeManager.DISABLE_CAR_MODE_GO_HOME) != 0) {
955 category = Intent.CATEGORY_HOME;
956 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800957 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +0100958
Jeff Brown487bb6e2012-10-11 13:35:42 -0700959 if (LOG) {
960 Slog.v(TAG, "updateLocked: null action, mDockState="
961 + mDockState +", category=" + category);
962 }
Daniel Sandler69a1da42011-11-04 15:08:30 -0400963
Jeff Brown487bb6e2012-10-11 13:35:42 -0700964 sendConfigurationAndStartDreamOrDockAppLocked(category);
965 }
Jeff Brown62c82e42012-09-26 01:30:41 -0700966
Jeff Brown487bb6e2012-10-11 13:35:42 -0700967 // keep screen on when charging and in car mode
968 boolean keepScreenOn = mCharging &&
keunyoung1d0a7cc2014-07-28 13:12:50 -0700969 ((mCarModeEnabled && mCarModeKeepsScreenOn &&
keunyoungc093bf22014-08-11 18:51:15 -0700970 (mCarModeEnableFlags & UiModeManager.ENABLE_CAR_MODE_ALLOW_SLEEP) == 0) ||
Jeff Brown487bb6e2012-10-11 13:35:42 -0700971 (mCurUiMode == Configuration.UI_MODE_TYPE_DESK && mDeskModeKeepsScreenOn));
972 if (keepScreenOn != mWakeLock.isHeld()) {
973 if (keepScreenOn) {
974 mWakeLock.acquire();
Dianne Hackbornf5c5d222010-04-09 13:14:48 -0700975 } else {
Jeff Brown487bb6e2012-10-11 13:35:42 -0700976 mWakeLock.release();
Dianne Hackborn7299c412010-03-04 18:41:49 -0800977 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800978 }
979 }
980
Adrian Roos2fbf4d52016-10-20 14:40:51 -0700981 private void sendForegroundBroadcastToAllUsers(String action) {
982 getContext().sendBroadcastAsUser(new Intent(action)
983 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND), UserHandle.ALL);
984 }
985
Jeff Brown62c82e42012-09-26 01:30:41 -0700986 private void updateAfterBroadcastLocked(String action, int enableFlags, int disableFlags) {
987 // Launch a dock activity
988 String category = null;
989 if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(action)) {
990 // Only launch car home when car mode is enabled and the caller
991 // has asked us to switch to it.
keunyounga7710492015-09-23 11:33:58 -0700992 if (mEnableCarDockLaunch
Jeff Brown62c82e42012-09-26 01:30:41 -0700993 && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
994 category = Intent.CATEGORY_CAR_DOCK;
995 }
996 } else if (UiModeManager.ACTION_ENTER_DESK_MODE.equals(action)) {
997 // Only launch car home when desk mode is enabled and the caller
998 // has asked us to switch to it. Currently re-using the car
999 // mode flag since we don't have a formal API for "desk mode".
1000 if (ENABLE_LAUNCH_DESK_DOCK_APP
1001 && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
1002 category = Intent.CATEGORY_DESK_DOCK;
1003 }
1004 } else {
1005 // Launch the standard home app if requested.
1006 if ((disableFlags & UiModeManager.DISABLE_CAR_MODE_GO_HOME) != 0) {
1007 category = Intent.CATEGORY_HOME;
1008 }
1009 }
1010
1011 if (LOG) {
1012 Slog.v(TAG, String.format(
1013 "Handling broadcast result for action %s: enable=0x%08x, disable=0x%08x, "
1014 + "category=%s",
1015 action, enableFlags, disableFlags, category));
1016 }
1017
1018 sendConfigurationAndStartDreamOrDockAppLocked(category);
1019 }
1020
1021 private void sendConfigurationAndStartDreamOrDockAppLocked(String category) {
1022 // Update the configuration but don't send it yet.
1023 mHoldingConfiguration = false;
1024 updateConfigurationLocked();
1025
1026 // Start the dock app, if there is one.
1027 boolean dockAppStarted = false;
1028 if (category != null) {
1029 // Now we are going to be careful about switching the
1030 // configuration and starting the activity -- we need to
1031 // do this in a specific order under control of the
1032 // activity manager, to do it cleanly. So compute the
1033 // new config, but don't set it yet, and let the
1034 // activity manager take care of both the start and config
1035 // change.
1036 Intent homeIntent = buildHomeIntent(category);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001037 if (Sandman.shouldStartDockApp(getContext(), homeIntent)) {
Jeff Brown11159e92012-10-11 15:58:37 -07001038 try {
Wale Ogunwale04d9cb52018-04-30 13:55:07 -07001039 int result = ActivityTaskManager.getService().startActivityWithConfig(
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001040 null, null, homeIntent, null, null, null, 0, 0,
Jeff Brown11159e92012-10-11 15:58:37 -07001041 mConfiguration, null, UserHandle.USER_CURRENT);
Bryce Lee7f936862017-05-09 15:33:18 -07001042 if (ActivityManager.isStartResultSuccessful(result)) {
Jeff Brown11159e92012-10-11 15:58:37 -07001043 dockAppStarted = true;
1044 } else if (result != ActivityManager.START_INTENT_NOT_RESOLVED) {
1045 Slog.e(TAG, "Could not start dock app: " + homeIntent
1046 + ", startActivityWithConfig result " + result);
1047 }
1048 } catch (RemoteException ex) {
1049 Slog.e(TAG, "Could not start dock app: " + homeIntent, ex);
Jeff Brown62c82e42012-09-26 01:30:41 -07001050 }
Jeff Brown62c82e42012-09-26 01:30:41 -07001051 }
1052 }
1053
1054 // Send the new configuration.
1055 sendConfigurationLocked();
1056
1057 // If we did not start a dock app, then start dreaming if supported.
Jeff Brown11159e92012-10-11 15:58:37 -07001058 if (category != null && !dockAppStarted) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001059 Sandman.startDreamWhenDockedIfAppropriate(getContext());
Jeff Brown62c82e42012-09-26 01:30:41 -07001060 }
1061 }
1062
Dianne Hackborn7299c412010-03-04 18:41:49 -08001063 private void adjustStatusBarCarModeLocked() {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001064 final Context context = getContext();
Dianne Hackborn7299c412010-03-04 18:41:49 -08001065 if (mStatusBarManager == null) {
Jeff Brown487bb6e2012-10-11 13:35:42 -07001066 mStatusBarManager = (StatusBarManager)
Adam Lesinski182f73f2013-12-05 16:48:06 -08001067 context.getSystemService(Context.STATUS_BAR_SERVICE);
Dianne Hackborn7299c412010-03-04 18:41:49 -08001068 }
1069
Joe Onorato089de882010-04-12 08:18:45 -07001070 // Fear not: StatusBarManagerService manages a list of requests to disable
Dianne Hackborn7299c412010-03-04 18:41:49 -08001071 // features of the status bar; these are ORed together to form the
1072 // active disabled list. So if (for example) the device is locked and
1073 // the status bar should be totally disabled, the calls below will
1074 // have no effect until the device is unlocked.
1075 if (mStatusBarManager != null) {
1076 mStatusBarManager.disable(mCarModeEnabled
1077 ? StatusBarManager.DISABLE_NOTIFICATION_TICKER
1078 : StatusBarManager.DISABLE_NONE);
1079 }
1080
1081 if (mNotificationManager == null) {
1082 mNotificationManager = (NotificationManager)
Adam Lesinski182f73f2013-12-05 16:48:06 -08001083 context.getSystemService(Context.NOTIFICATION_SERVICE);
Dianne Hackborn7299c412010-03-04 18:41:49 -08001084 }
1085
1086 if (mNotificationManager != null) {
1087 if (mCarModeEnabled) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001088 Intent carModeOffIntent = new Intent(context, DisableCarModeActivity.class);
Dianne Hackborn7299c412010-03-04 18:41:49 -08001089
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05001090 Notification.Builder n =
1091 new Notification.Builder(context, SystemNotificationChannels.CAR_MODE)
Chris Wren1ce4b6d2015-06-11 10:19:43 -04001092 .setSmallIcon(R.drawable.stat_notify_car_mode)
1093 .setDefaults(Notification.DEFAULT_LIGHTS)
1094 .setOngoing(true)
1095 .setWhen(0)
1096 .setColor(context.getColor(
1097 com.android.internal.R.color.system_notification_accent_color))
1098 .setContentTitle(
1099 context.getString(R.string.car_mode_disable_notification_title))
1100 .setContentText(
1101 context.getString(R.string.car_mode_disable_notification_message))
1102 .setContentIntent(
1103 PendingIntent.getActivityAsUser(context, 0, carModeOffIntent, 0,
1104 null, UserHandle.CURRENT));
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07001105 mNotificationManager.notifyAsUser(null,
Chris Wren282cfef2017-03-27 15:01:44 -04001106 SystemMessage.NOTE_CAR_MODE_DISABLE, n.build(), UserHandle.ALL);
Dianne Hackborn7299c412010-03-04 18:41:49 -08001107 } else {
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07001108 mNotificationManager.cancelAsUser(null,
Chris Wren282cfef2017-03-27 15:01:44 -04001109 SystemMessage.NOTE_CAR_MODE_DISABLE, UserHandle.ALL);
Dianne Hackborn7299c412010-03-04 18:41:49 -08001110 }
1111 }
1112 }
1113
Jeff Brown2416e092012-08-21 22:12:20 -07001114 private void updateComputedNightModeLocked() {
Adam Lesinski05199e82015-03-19 14:37:11 -07001115 if (mTwilightManager != null) {
Justin Klaassen908b86c2016-08-08 09:18:42 -07001116 TwilightState state = mTwilightManager.getLastTwilightState();
Adam Lesinski05199e82015-03-19 14:37:11 -07001117 if (state != null) {
1118 mComputedNightMode = state.isNight();
1119 }
Jay Aliomer8b2671b2019-10-24 13:18:06 -04001120 if (mNightModeOverride == UiModeManager.MODE_NIGHT_YES && !mComputedNightMode) {
1121 mComputedNightMode = true;
1122 return;
1123 }
1124 if (mNightModeOverride == UiModeManager.MODE_NIGHT_NO && mComputedNightMode) {
1125 mComputedNightMode = false;
1126 return;
1127 }
1128
1129 mNightModeOverride = mNightMode;
1130 final int user = UserHandle.getCallingUserId();
1131 Secure.putIntForUser(getContext().getContentResolver(),
1132 OVERRIDE_NIGHT_MODE, mNightModeOverride, user);
1133
Dianne Hackborn7299c412010-03-04 18:41:49 -08001134 }
Dianne Hackborn7299c412010-03-04 18:41:49 -08001135 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +01001136
Zak Cohen1a705732017-01-09 12:54:34 -08001137 private void registerVrStateListener() {
Craig Donner8deb67c2017-02-07 18:10:32 -08001138 IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService(
1139 Context.VR_SERVICE));
Zak Cohen1a705732017-01-09 12:54:34 -08001140 try {
1141 if (vrManager != null) {
1142 vrManager.registerListener(mVrStateCallbacks);
1143 }
1144 } catch (RemoteException e) {
1145 Slog.e(TAG, "Failed to register VR mode state listener: " + e);
1146 }
1147 }
Bernd Holzheyba9ab182010-03-12 09:30:29 +01001148
Alan Viveretteba0d98f2017-01-30 10:36:54 -05001149 /**
1150 * Handles "adb shell" commands.
1151 */
1152 private static class Shell extends ShellCommand {
1153 public static final String NIGHT_MODE_STR_YES = "yes";
1154 public static final String NIGHT_MODE_STR_NO = "no";
1155 public static final String NIGHT_MODE_STR_AUTO = "auto";
1156 public static final String NIGHT_MODE_STR_UNKNOWN = "unknown";
1157 private final IUiModeManager mInterface;
1158
1159 Shell(IUiModeManager iface) {
1160 mInterface = iface;
1161 }
1162
1163 @Override
1164 public void onHelp() {
1165 final PrintWriter pw = getOutPrintWriter();
1166 pw.println("UiModeManager service (uimode) commands:");
1167 pw.println(" help");
1168 pw.println(" Print this help text.");
1169 pw.println(" night [yes|no|auto]");
1170 pw.println(" Set or read night mode.");
1171 }
1172
1173 @Override
1174 public int onCommand(String cmd) {
1175 if (cmd == null) {
1176 return handleDefaultCommands(cmd);
1177 }
1178
1179 try {
1180 switch (cmd) {
1181 case "night":
1182 return handleNightMode();
1183 default:
1184 return handleDefaultCommands(cmd);
1185 }
1186 } catch (RemoteException e) {
1187 final PrintWriter err = getErrPrintWriter();
1188 err.println("Remote exception: " + e);
1189 }
1190 return -1;
1191 }
1192
1193 private int handleNightMode() throws RemoteException {
1194 final PrintWriter err = getErrPrintWriter();
1195 final String modeStr = getNextArg();
1196 if (modeStr == null) {
1197 printCurrentNightMode();
1198 return 0;
1199 }
1200
1201 final int mode = strToNightMode(modeStr);
1202 if (mode >= 0) {
1203 mInterface.setNightMode(mode);
1204 printCurrentNightMode();
1205 return 0;
1206 } else {
1207 err.println("Error: mode must be '" + NIGHT_MODE_STR_YES + "', '"
1208 + NIGHT_MODE_STR_NO + "', or '" + NIGHT_MODE_STR_AUTO + "'");
1209 return -1;
1210 }
1211 }
1212
1213 private void printCurrentNightMode() throws RemoteException {
1214 final PrintWriter pw = getOutPrintWriter();
1215 final int currMode = mInterface.getNightMode();
1216 final String currModeStr = nightModeToStr(currMode);
1217 pw.println("Night mode: " + currModeStr);
1218 }
1219
1220 private static String nightModeToStr(int mode) {
1221 switch (mode) {
1222 case UiModeManager.MODE_NIGHT_YES:
1223 return NIGHT_MODE_STR_YES;
1224 case UiModeManager.MODE_NIGHT_NO:
1225 return NIGHT_MODE_STR_NO;
1226 case UiModeManager.MODE_NIGHT_AUTO:
1227 return NIGHT_MODE_STR_AUTO;
1228 default:
1229 return NIGHT_MODE_STR_UNKNOWN;
1230 }
1231 }
1232
1233 private static int strToNightMode(String modeStr) {
1234 switch (modeStr) {
1235 case NIGHT_MODE_STR_YES:
1236 return UiModeManager.MODE_NIGHT_YES;
1237 case NIGHT_MODE_STR_NO:
1238 return UiModeManager.MODE_NIGHT_NO;
1239 case NIGHT_MODE_STR_AUTO:
1240 return UiModeManager.MODE_NIGHT_AUTO;
1241 default:
1242 return -1;
1243 }
1244 }
1245 }
Felipe Lemeff9ec382018-09-24 11:07:56 -07001246
1247 public final class LocalService extends UiModeManagerInternal {
1248
1249 @Override
1250 public boolean isNightMode() {
1251 synchronized (mLock) {
1252 final boolean isIt = (mConfiguration.uiMode & Configuration.UI_MODE_NIGHT_YES) != 0;
1253 if (LOG) {
1254 Slog.d(TAG,
1255 "LocalService.isNightMode(): mNightMode=" + mNightMode
1256 + "; mComputedNightMode=" + mComputedNightMode
1257 + "; uiMode=" + mConfiguration.uiMode
1258 + "; isIt=" + isIt);
1259 }
1260 return isIt;
1261 }
1262 }
1263 }
Salvador Martinez2f792ef2018-09-26 17:33:51 -07001264
1265 private final class UserSwitchedReceiver extends BroadcastReceiver {
1266 @Override
1267 public void onReceive(Context context, Intent intent) {
1268 synchronized (mLock) {
1269 final int currentId = intent.getIntExtra(
1270 Intent.EXTRA_USER_HANDLE, UserHandle.USER_SYSTEM);
1271 // only update if the value is actually changed
1272 if (updateNightModeFromSettings(context, context.getResources(), currentId)) {
1273 updateLocked(0, 0);
1274 }
1275 }
1276 }
1277 }
Dianne Hackborn7299c412010-03-04 18:41:49 -08001278}