blob: 9b54a7073c70f250b2e2e4ae93c3a4d39cbbf6dd [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
19import com.android.internal.app.IBatteryStats;
20import com.android.server.am.BatteryStatsService;
21
22import android.app.ActivityManagerNative;
23import android.app.IActivityManager;
24import android.content.BroadcastReceiver;
25import android.content.ContentQueryMap;
26import android.content.ContentResolver;
27import android.content.Context;
28import android.content.Intent;
29import android.content.IntentFilter;
30import android.content.pm.PackageManager;
Mike Lockwoodd7786b42009-10-15 17:09:16 -070031import android.content.res.Resources;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.database.Cursor;
Mike Lockwoodbc706a02009-07-27 13:50:57 -070033import android.hardware.Sensor;
34import android.hardware.SensorEvent;
35import android.hardware.SensorEventListener;
36import android.hardware.SensorManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.os.BatteryStats;
38import android.os.Binder;
39import android.os.Handler;
40import android.os.HandlerThread;
41import android.os.IBinder;
42import android.os.IPowerManager;
43import android.os.LocalPowerManager;
44import android.os.Power;
45import android.os.PowerManager;
46import android.os.Process;
47import android.os.RemoteException;
48import android.os.SystemClock;
49import android.provider.Settings.SettingNotFoundException;
50import android.provider.Settings;
51import android.util.EventLog;
52import android.util.Log;
53import android.view.WindowManagerPolicy;
54import static android.provider.Settings.System.DIM_SCREEN;
55import static android.provider.Settings.System.SCREEN_BRIGHTNESS;
Dan Murphy951764b2009-08-27 14:59:03 -050056import static android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE;
Mike Lockwooddc3494e2009-10-14 21:17:09 -070057import static android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
59import static android.provider.Settings.System.STAY_ON_WHILE_PLUGGED_IN;
60
61import java.io.FileDescriptor;
62import java.io.PrintWriter;
63import java.util.ArrayList;
64import java.util.HashMap;
65import java.util.Observable;
66import java.util.Observer;
67
Mike Lockwoodbc706a02009-07-27 13:50:57 -070068class PowerManagerService extends IPowerManager.Stub
Mike Lockwood8738e0c2009-10-04 08:44:47 -040069 implements LocalPowerManager, Watchdog.Monitor {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070
71 private static final String TAG = "PowerManagerService";
72 static final String PARTIAL_NAME = "PowerManagerService";
73
74 private static final boolean LOG_PARTIAL_WL = false;
75
76 // Indicates whether touch-down cycles should be logged as part of the
77 // LOG_POWER_SCREEN_STATE log events
78 private static final boolean LOG_TOUCH_DOWNS = true;
79
80 private static final int LOCK_MASK = PowerManager.PARTIAL_WAKE_LOCK
81 | PowerManager.SCREEN_DIM_WAKE_LOCK
82 | PowerManager.SCREEN_BRIGHT_WAKE_LOCK
Mike Lockwoodbc706a02009-07-27 13:50:57 -070083 | PowerManager.FULL_WAKE_LOCK
84 | PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085
86 // time since last state: time since last event:
87 // The short keylight delay comes from Gservices; this is the default.
88 private static final int SHORT_KEYLIGHT_DELAY_DEFAULT = 6000; // t+6 sec
89 private static final int MEDIUM_KEYLIGHT_DELAY = 15000; // t+15 sec
90 private static final int LONG_KEYLIGHT_DELAY = 6000; // t+6 sec
91 private static final int LONG_DIM_TIME = 7000; // t+N-5 sec
92
Mike Lockwoodd7786b42009-10-15 17:09:16 -070093 // How long to wait to debounce light sensor changes.
94 private static final int LIGHT_SENSOR_DELAY = 1000;
95
Mike Lockwoodd20ea362009-09-15 00:13:38 -040096 // trigger proximity if distance is less than 5 cm
97 private static final float PROXIMITY_THRESHOLD = 5.0f;
98
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099 // Cached Gservices settings; see updateGservicesValues()
100 private int mShortKeylightDelay = SHORT_KEYLIGHT_DELAY_DEFAULT;
101
102 // flags for setPowerState
103 private static final int SCREEN_ON_BIT = 0x00000001;
104 private static final int SCREEN_BRIGHT_BIT = 0x00000002;
105 private static final int BUTTON_BRIGHT_BIT = 0x00000004;
106 private static final int KEYBOARD_BRIGHT_BIT = 0x00000008;
107 private static final int BATTERY_LOW_BIT = 0x00000010;
108
109 // values for setPowerState
110
111 // SCREEN_OFF == everything off
112 private static final int SCREEN_OFF = 0x00000000;
113
114 // SCREEN_DIM == screen on, screen backlight dim
115 private static final int SCREEN_DIM = SCREEN_ON_BIT;
116
117 // SCREEN_BRIGHT == screen on, screen backlight bright
118 private static final int SCREEN_BRIGHT = SCREEN_ON_BIT | SCREEN_BRIGHT_BIT;
119
120 // SCREEN_BUTTON_BRIGHT == screen on, screen and button backlights bright
121 private static final int SCREEN_BUTTON_BRIGHT = SCREEN_BRIGHT | BUTTON_BRIGHT_BIT;
122
123 // SCREEN_BUTTON_BRIGHT == screen on, screen, button and keyboard backlights bright
124 private static final int ALL_BRIGHT = SCREEN_BUTTON_BRIGHT | KEYBOARD_BRIGHT_BIT;
125
126 // used for noChangeLights in setPowerState()
127 private static final int LIGHTS_MASK = SCREEN_BRIGHT_BIT | BUTTON_BRIGHT_BIT | KEYBOARD_BRIGHT_BIT;
128
129 static final boolean ANIMATE_SCREEN_LIGHTS = true;
130 static final boolean ANIMATE_BUTTON_LIGHTS = false;
131 static final boolean ANIMATE_KEYBOARD_LIGHTS = false;
132
133 static final int ANIM_STEPS = 60/4;
134
135 // These magic numbers are the initial state of the LEDs at boot. Ideally
136 // we should read them from the driver, but our current hardware returns 0
137 // for the initial value. Oops!
138 static final int INITIAL_SCREEN_BRIGHTNESS = 255;
139 static final int INITIAL_BUTTON_BRIGHTNESS = Power.BRIGHTNESS_OFF;
140 static final int INITIAL_KEYBOARD_BRIGHTNESS = Power.BRIGHTNESS_OFF;
141
142 static final int LOG_POWER_SLEEP_REQUESTED = 2724;
143 static final int LOG_POWER_SCREEN_BROADCAST_SEND = 2725;
144 static final int LOG_POWER_SCREEN_BROADCAST_DONE = 2726;
145 static final int LOG_POWER_SCREEN_BROADCAST_STOP = 2727;
146 static final int LOG_POWER_SCREEN_STATE = 2728;
147 static final int LOG_POWER_PARTIAL_WAKE_STATE = 2729;
148
149 private final int MY_UID;
150
151 private boolean mDoneBooting = false;
152 private int mStayOnConditions = 0;
Joe Onorato128e7292009-03-24 18:41:31 -0700153 private int[] mBroadcastQueue = new int[] { -1, -1, -1 };
154 private int[] mBroadcastWhy = new int[3];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 private int mPartialCount = 0;
Mike Lockwoodbc706a02009-07-27 13:50:57 -0700156 private int mProximityCount = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157 private int mPowerState;
158 private boolean mOffBecauseOfUser;
159 private int mUserState;
160 private boolean mKeyboardVisible = false;
161 private boolean mUserActivityAllowed = true;
Mike Lockwood36fc3022009-08-25 16:49:06 -0700162 private boolean mProximitySensorActive = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163 private int mTotalDelaySetting;
164 private int mKeylightDelay;
165 private int mDimDelay;
166 private int mScreenOffDelay;
167 private int mWakeLockState;
168 private long mLastEventTime = 0;
169 private long mScreenOffTime;
170 private volatile WindowManagerPolicy mPolicy;
171 private final LockList mLocks = new LockList();
172 private Intent mScreenOffIntent;
173 private Intent mScreenOnIntent;
The Android Open Source Project10592532009-03-18 17:39:46 -0700174 private HardwareService mHardware;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175 private Context mContext;
176 private UnsynchronizedWakeLock mBroadcastWakeLock;
177 private UnsynchronizedWakeLock mStayOnWhilePluggedInScreenDimLock;
178 private UnsynchronizedWakeLock mStayOnWhilePluggedInPartialLock;
179 private UnsynchronizedWakeLock mPreventScreenOnPartialLock;
180 private HandlerThread mHandlerThread;
181 private Handler mHandler;
182 private TimeoutTask mTimeoutTask = new TimeoutTask();
183 private LightAnimator mLightAnimator = new LightAnimator();
184 private final BrightnessState mScreenBrightness
The Android Open Source Project10592532009-03-18 17:39:46 -0700185 = new BrightnessState(SCREEN_BRIGHT_BIT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186 private final BrightnessState mKeyboardBrightness
The Android Open Source Project10592532009-03-18 17:39:46 -0700187 = new BrightnessState(KEYBOARD_BRIGHT_BIT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188 private final BrightnessState mButtonBrightness
The Android Open Source Project10592532009-03-18 17:39:46 -0700189 = new BrightnessState(BUTTON_BRIGHT_BIT);
Joe Onorato128e7292009-03-24 18:41:31 -0700190 private boolean mStillNeedSleepNotification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191 private boolean mIsPowered = false;
192 private IActivityManager mActivityService;
193 private IBatteryStats mBatteryStats;
194 private BatteryService mBatteryService;
Mike Lockwoodbc706a02009-07-27 13:50:57 -0700195 private SensorManager mSensorManager;
196 private Sensor mProximitySensor;
Mike Lockwood8738e0c2009-10-04 08:44:47 -0400197 private Sensor mLightSensor;
198 private boolean mLightSensorEnabled;
199 private float mLightSensorValue = -1;
Mike Lockwoodd7786b42009-10-15 17:09:16 -0700200 private float mLightSensorPendingValue = -1;
201 private int mLightSensorBrightness = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202 private boolean mDimScreen = true;
203 private long mNextTimeout;
204 private volatile int mPokey = 0;
205 private volatile boolean mPokeAwakeOnSet = false;
206 private volatile boolean mInitComplete = false;
207 private HashMap<IBinder,PokeLock> mPokeLocks = new HashMap<IBinder,PokeLock>();
208 private long mScreenOnTime;
209 private long mScreenOnStartTime;
210 private boolean mPreventScreenOn;
211 private int mScreenBrightnessOverride = -1;
Mike Lockwooddc3494e2009-10-14 21:17:09 -0700212 private boolean mHasHardwareAutoBrightness;
213 private boolean mAutoBrightessEnabled;
Mike Lockwoodd7786b42009-10-15 17:09:16 -0700214 private int[] mAutoBrightnessLevels;
215 private int[] mLcdBacklightValues;
216 private int[] mButtonBacklightValues;
217 private int[] mKeyboardBacklightValues;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218
219 // Used when logging number and duration of touch-down cycles
220 private long mTotalTouchDownTime;
221 private long mLastTouchDown;
222 private int mTouchCycles;
223
224 // could be either static or controllable at runtime
225 private static final boolean mSpew = false;
Mike Lockwood8738e0c2009-10-04 08:44:47 -0400226 private static final boolean mDebugLightSensor = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227
228 /*
229 static PrintStream mLog;
230 static {
231 try {
232 mLog = new PrintStream("/data/power.log");
233 }
234 catch (FileNotFoundException e) {
235 android.util.Log.e(TAG, "Life is hard", e);
236 }
237 }
238 static class Log {
239 static void d(String tag, String s) {
240 mLog.println(s);
241 android.util.Log.d(tag, s);
242 }
243 static void i(String tag, String s) {
244 mLog.println(s);
245 android.util.Log.i(tag, s);
246 }
247 static void w(String tag, String s) {
248 mLog.println(s);
249 android.util.Log.w(tag, s);
250 }
251 static void e(String tag, String s) {
252 mLog.println(s);
253 android.util.Log.e(tag, s);
254 }
255 }
256 */
257
258 /**
259 * This class works around a deadlock between the lock in PowerManager.WakeLock
260 * and our synchronizing on mLocks. PowerManager.WakeLock synchronizes on its
261 * mToken object so it can be accessed from any thread, but it calls into here
262 * with its lock held. This class is essentially a reimplementation of
263 * PowerManager.WakeLock, but without that extra synchronized block, because we'll
264 * only call it with our own locks held.
265 */
266 private class UnsynchronizedWakeLock {
267 int mFlags;
268 String mTag;
269 IBinder mToken;
270 int mCount = 0;
271 boolean mRefCounted;
272
273 UnsynchronizedWakeLock(int flags, String tag, boolean refCounted) {
274 mFlags = flags;
275 mTag = tag;
276 mToken = new Binder();
277 mRefCounted = refCounted;
278 }
279
280 public void acquire() {
281 if (!mRefCounted || mCount++ == 0) {
282 long ident = Binder.clearCallingIdentity();
283 try {
284 PowerManagerService.this.acquireWakeLockLocked(mFlags, mToken,
285 MY_UID, mTag);
286 } finally {
287 Binder.restoreCallingIdentity(ident);
288 }
289 }
290 }
291
292 public void release() {
293 if (!mRefCounted || --mCount == 0) {
294 PowerManagerService.this.releaseWakeLockLocked(mToken, false);
295 }
296 if (mCount < 0) {
297 throw new RuntimeException("WakeLock under-locked " + mTag);
298 }
299 }
300
301 public String toString() {
302 return "UnsynchronizedWakeLock(mFlags=0x" + Integer.toHexString(mFlags)
303 + " mCount=" + mCount + ")";
304 }
305 }
306
307 private final class BatteryReceiver extends BroadcastReceiver {
308 @Override
309 public void onReceive(Context context, Intent intent) {
310 synchronized (mLocks) {
311 boolean wasPowered = mIsPowered;
312 mIsPowered = mBatteryService.isPowered();
313
314 if (mIsPowered != wasPowered) {
315 // update mStayOnWhilePluggedIn wake lock
316 updateWakeLockLocked();
317
318 // treat plugging and unplugging the devices as a user activity.
319 // users find it disconcerting when they unplug the device
320 // and it shuts off right away.
321 // temporarily set mUserActivityAllowed to true so this will work
322 // even when the keyguard is on.
323 synchronized (mLocks) {
Mike Lockwood200b30b2009-09-20 00:23:59 -0400324 forceUserActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325 }
326 }
327 }
328 }
329 }
330
331 /**
332 * Set the setting that determines whether the device stays on when plugged in.
333 * The argument is a bit string, with each bit specifying a power source that,
334 * when the device is connected to that source, causes the device to stay on.
335 * See {@link android.os.BatteryManager} for the list of power sources that
336 * can be specified. Current values include {@link android.os.BatteryManager#BATTERY_PLUGGED_AC}
337 * and {@link android.os.BatteryManager#BATTERY_PLUGGED_USB}
338 * @param val an {@code int} containing the bits that specify which power sources
339 * should cause the device to stay on.
340 */
341 public void setStayOnSetting(int val) {
342 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SETTINGS, null);
343 Settings.System.putInt(mContext.getContentResolver(),
344 Settings.System.STAY_ON_WHILE_PLUGGED_IN, val);
345 }
346
347 private class SettingsObserver implements Observer {
348 private int getInt(String name) {
349 return mSettings.getValues(name).getAsInteger(Settings.System.VALUE);
350 }
351
352 public void update(Observable o, Object arg) {
353 synchronized (mLocks) {
354 // STAY_ON_WHILE_PLUGGED_IN
355 mStayOnConditions = getInt(STAY_ON_WHILE_PLUGGED_IN);
356 updateWakeLockLocked();
357
358 // SCREEN_OFF_TIMEOUT
359 mTotalDelaySetting = getInt(SCREEN_OFF_TIMEOUT);
360
361 // DIM_SCREEN
362 //mDimScreen = getInt(DIM_SCREEN) != 0;
363
Mike Lockwooddc3494e2009-10-14 21:17:09 -0700364 // SCREEN_BRIGHTNESS_MODE
365 setScreenBrightnessMode(getInt(SCREEN_BRIGHTNESS_MODE));
366
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 // recalculate everything
368 setScreenOffTimeoutsLocked();
369 }
370 }
371 }
372
373 PowerManagerService()
374 {
375 // Hack to get our uid... should have a func for this.
376 long token = Binder.clearCallingIdentity();
377 MY_UID = Binder.getCallingUid();
378 Binder.restoreCallingIdentity(token);
379
380 // XXX remove this when the kernel doesn't timeout wake locks
381 Power.setLastUserActivityTimeout(7*24*3600*1000); // one week
382
383 // assume nothing is on yet
384 mUserState = mPowerState = 0;
385
386 // Add ourself to the Watchdog monitors.
387 Watchdog.getInstance().addMonitor(this);
388 mScreenOnStartTime = SystemClock.elapsedRealtime();
389 }
390
391 private ContentQueryMap mSettings;
392
The Android Open Source Project10592532009-03-18 17:39:46 -0700393 void init(Context context, HardwareService hardware, IActivityManager activity,
394 BatteryService battery) {
395 mHardware = hardware;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 mContext = context;
397 mActivityService = activity;
398 mBatteryStats = BatteryStatsService.getService();
399 mBatteryService = battery;
400
401 mHandlerThread = new HandlerThread("PowerManagerService") {
402 @Override
403 protected void onLooperPrepared() {
404 super.onLooperPrepared();
405 initInThread();
406 }
407 };
408 mHandlerThread.start();
409
410 synchronized (mHandlerThread) {
411 while (!mInitComplete) {
412 try {
413 mHandlerThread.wait();
414 } catch (InterruptedException e) {
415 // Ignore
416 }
417 }
418 }
419 }
420
421 void initInThread() {
422 mHandler = new Handler();
423
424 mBroadcastWakeLock = new UnsynchronizedWakeLock(
Joe Onorato128e7292009-03-24 18:41:31 -0700425 PowerManager.PARTIAL_WAKE_LOCK, "sleep_broadcast", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800426 mStayOnWhilePluggedInScreenDimLock = new UnsynchronizedWakeLock(
427 PowerManager.SCREEN_DIM_WAKE_LOCK, "StayOnWhilePluggedIn Screen Dim", false);
428 mStayOnWhilePluggedInPartialLock = new UnsynchronizedWakeLock(
429 PowerManager.PARTIAL_WAKE_LOCK, "StayOnWhilePluggedIn Partial", false);
430 mPreventScreenOnPartialLock = new UnsynchronizedWakeLock(
431 PowerManager.PARTIAL_WAKE_LOCK, "PreventScreenOn Partial", false);
432
433 mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
434 mScreenOnIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
435 mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF);
436 mScreenOffIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
437
Mike Lockwoodd7786b42009-10-15 17:09:16 -0700438 Resources resources = mContext.getResources();
439 mHasHardwareAutoBrightness = resources.getBoolean(
Mike Lockwooddc3494e2009-10-14 21:17:09 -0700440 com.android.internal.R.bool.config_hardware_automatic_brightness_available);
Mike Lockwoodd7786b42009-10-15 17:09:16 -0700441 if (!mHasHardwareAutoBrightness) {
442 mAutoBrightnessLevels = resources.getIntArray(
443 com.android.internal.R.array.config_autoBrightnessLevels);
444 mLcdBacklightValues = resources.getIntArray(
445 com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
446 mButtonBacklightValues = resources.getIntArray(
447 com.android.internal.R.array.config_autoBrightnessButtonBacklightValues);
448 mKeyboardBacklightValues = resources.getIntArray(
449 com.android.internal.R.array.config_autoBrightnessKeyboardBacklightValues);
450 }
Mike Lockwooddc3494e2009-10-14 21:17:09 -0700451
452 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800453 Cursor settingsCursor = resolver.query(Settings.System.CONTENT_URI, null,
454 "(" + Settings.System.NAME + "=?) or ("
455 + Settings.System.NAME + "=?) or ("
Mike Lockwooddc3494e2009-10-14 21:17:09 -0700456 + Settings.System.NAME + "=?) or ("
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 + Settings.System.NAME + "=?)",
Mike Lockwooddc3494e2009-10-14 21:17:09 -0700458 new String[]{STAY_ON_WHILE_PLUGGED_IN, SCREEN_OFF_TIMEOUT, DIM_SCREEN,
459 SCREEN_BRIGHTNESS_MODE},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800460 null);
461 mSettings = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, mHandler);
462 SettingsObserver settingsObserver = new SettingsObserver();
463 mSettings.addObserver(settingsObserver);
464
465 // pretend that the settings changed so we will get their initial state
466 settingsObserver.update(mSettings, null);
467
468 // register for the battery changed notifications
469 IntentFilter filter = new IntentFilter();
470 filter.addAction(Intent.ACTION_BATTERY_CHANGED);
471 mContext.registerReceiver(new BatteryReceiver(), filter);
472
473 // Listen for Gservices changes
474 IntentFilter gservicesChangedFilter =
475 new IntentFilter(Settings.Gservices.CHANGED_ACTION);
476 mContext.registerReceiver(new GservicesChangedReceiver(), gservicesChangedFilter);
477 // And explicitly do the initial update of our cached settings
478 updateGservicesValues();
479
Mike Lockwood6c97fca2009-10-20 08:10:00 -0400480 if (mAutoBrightessEnabled) {
481 // turn the screen on
482 setPowerState(SCREEN_BRIGHT);
483 } else {
484 // turn everything on
485 setPowerState(ALL_BRIGHT);
486 }
Dan Murphy951764b2009-08-27 14:59:03 -0500487
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800488 synchronized (mHandlerThread) {
489 mInitComplete = true;
490 mHandlerThread.notifyAll();
491 }
492 }
493
494 private class WakeLock implements IBinder.DeathRecipient
495 {
496 WakeLock(int f, IBinder b, String t, int u) {
497 super();
498 flags = f;
499 binder = b;
500 tag = t;
501 uid = u == MY_UID ? Process.SYSTEM_UID : u;
502 if (u != MY_UID || (
503 !"KEEP_SCREEN_ON_FLAG".equals(tag)
504 && !"KeyInputQueue".equals(tag))) {
505 monitorType = (f & LOCK_MASK) == PowerManager.PARTIAL_WAKE_LOCK
506 ? BatteryStats.WAKE_TYPE_PARTIAL
507 : BatteryStats.WAKE_TYPE_FULL;
508 } else {
509 monitorType = -1;
510 }
511 try {
512 b.linkToDeath(this, 0);
513 } catch (RemoteException e) {
514 binderDied();
515 }
516 }
517 public void binderDied() {
518 synchronized (mLocks) {
519 releaseWakeLockLocked(this.binder, true);
520 }
521 }
522 final int flags;
523 final IBinder binder;
524 final String tag;
525 final int uid;
526 final int monitorType;
527 boolean activated = true;
528 int minState;
529 }
530
531 private void updateWakeLockLocked() {
532 if (mStayOnConditions != 0 && mBatteryService.isPowered(mStayOnConditions)) {
533 // keep the device on if we're plugged in and mStayOnWhilePluggedIn is set.
534 mStayOnWhilePluggedInScreenDimLock.acquire();
535 mStayOnWhilePluggedInPartialLock.acquire();
536 } else {
537 mStayOnWhilePluggedInScreenDimLock.release();
538 mStayOnWhilePluggedInPartialLock.release();
539 }
540 }
541
542 private boolean isScreenLock(int flags)
543 {
544 int n = flags & LOCK_MASK;
545 return n == PowerManager.FULL_WAKE_LOCK
546 || n == PowerManager.SCREEN_BRIGHT_WAKE_LOCK
547 || n == PowerManager.SCREEN_DIM_WAKE_LOCK;
548 }
549
550 public void acquireWakeLock(int flags, IBinder lock, String tag) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 int uid = Binder.getCallingUid();
Michael Chane96440f2009-05-06 10:27:36 -0700552 if (uid != Process.myUid()) {
553 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
554 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800555 long ident = Binder.clearCallingIdentity();
556 try {
557 synchronized (mLocks) {
558 acquireWakeLockLocked(flags, lock, uid, tag);
559 }
560 } finally {
561 Binder.restoreCallingIdentity(ident);
562 }
563 }
564
565 public void acquireWakeLockLocked(int flags, IBinder lock, int uid, String tag) {
566 int acquireUid = -1;
567 String acquireName = null;
568 int acquireType = -1;
569
570 if (mSpew) {
571 Log.d(TAG, "acquireWakeLock flags=0x" + Integer.toHexString(flags) + " tag=" + tag);
572 }
573
574 int index = mLocks.getIndex(lock);
575 WakeLock wl;
576 boolean newlock;
577 if (index < 0) {
578 wl = new WakeLock(flags, lock, tag, uid);
579 switch (wl.flags & LOCK_MASK)
580 {
581 case PowerManager.FULL_WAKE_LOCK:
Mike Lockwoodd7786b42009-10-15 17:09:16 -0700582 wl.minState = SCREEN_BRIGHT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583 break;
584 case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
585 wl.minState = SCREEN_BRIGHT;
586 break;
587 case PowerManager.SCREEN_DIM_WAKE_LOCK:
588 wl.minState = SCREEN_DIM;
589 break;
590 case PowerManager.PARTIAL_WAKE_LOCK:
Mike Lockwoodbc706a02009-07-27 13:50:57 -0700591 case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800592 break;
593 default:
594 // just log and bail. we're in the server, so don't
595 // throw an exception.
596 Log.e(TAG, "bad wakelock type for lock '" + tag + "' "
597 + " flags=" + flags);
598 return;
599 }
600 mLocks.addLock(wl);
601 newlock = true;
602 } else {
603 wl = mLocks.get(index);
604 newlock = false;
605 }
606 if (isScreenLock(flags)) {
607 // if this causes a wakeup, we reactivate all of the locks and
608 // set it to whatever they want. otherwise, we modulate that
609 // by the current state so we never turn it more on than
610 // it already is.
611 if ((wl.flags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0) {
Michael Chane96440f2009-05-06 10:27:36 -0700612 int oldWakeLockState = mWakeLockState;
613 mWakeLockState = mLocks.reactivateScreenLocksLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800614 if (mSpew) {
615 Log.d(TAG, "wakeup here mUserState=0x" + Integer.toHexString(mUserState)
Michael Chane96440f2009-05-06 10:27:36 -0700616 + " mWakeLockState=0x"
617 + Integer.toHexString(mWakeLockState)
618 + " previous wakeLockState=0x" + Integer.toHexString(oldWakeLockState));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800620 } else {
621 if (mSpew) {
622 Log.d(TAG, "here mUserState=0x" + Integer.toHexString(mUserState)
623 + " mLocks.gatherState()=0x"
624 + Integer.toHexString(mLocks.gatherState())
625 + " mWakeLockState=0x" + Integer.toHexString(mWakeLockState));
626 }
627 mWakeLockState = (mUserState | mWakeLockState) & mLocks.gatherState();
628 }
629 setPowerState(mWakeLockState | mUserState);
630 }
631 else if ((flags & LOCK_MASK) == PowerManager.PARTIAL_WAKE_LOCK) {
632 if (newlock) {
633 mPartialCount++;
634 if (mPartialCount == 1) {
635 if (LOG_PARTIAL_WL) EventLog.writeEvent(LOG_POWER_PARTIAL_WAKE_STATE, 1, tag);
636 }
637 }
638 Power.acquireWakeLock(Power.PARTIAL_WAKE_LOCK,PARTIAL_NAME);
Mike Lockwoodbc706a02009-07-27 13:50:57 -0700639 } else if ((flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) {
640 mProximityCount++;
641 if (mProximityCount == 1) {
642 enableProximityLockLocked();
643 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800644 }
645 if (newlock) {
646 acquireUid = wl.uid;
647 acquireName = wl.tag;
648 acquireType = wl.monitorType;
649 }
650
651 if (acquireType >= 0) {
652 try {
653 mBatteryStats.noteStartWakelock(acquireUid, acquireName, acquireType);
654 } catch (RemoteException e) {
655 // Ignore
656 }
657 }
658 }
659
660 public void releaseWakeLock(IBinder lock) {
Michael Chane96440f2009-05-06 10:27:36 -0700661 int uid = Binder.getCallingUid();
662 if (uid != Process.myUid()) {
663 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
664 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665
666 synchronized (mLocks) {
667 releaseWakeLockLocked(lock, false);
668 }
669 }
670
671 private void releaseWakeLockLocked(IBinder lock, boolean death) {
672 int releaseUid;
673 String releaseName;
674 int releaseType;
675
676 WakeLock wl = mLocks.removeLock(lock);
677 if (wl == null) {
678 return;
679 }
680
681 if (mSpew) {
682 Log.d(TAG, "releaseWakeLock flags=0x"
683 + Integer.toHexString(wl.flags) + " tag=" + wl.tag);
684 }
685
686 if (isScreenLock(wl.flags)) {
687 mWakeLockState = mLocks.gatherState();
688 // goes in the middle to reduce flicker
689 if ((wl.flags & PowerManager.ON_AFTER_RELEASE) != 0) {
690 userActivity(SystemClock.uptimeMillis(), false);
691 }
692 setPowerState(mWakeLockState | mUserState);
693 }
694 else if ((wl.flags & LOCK_MASK) == PowerManager.PARTIAL_WAKE_LOCK) {
695 mPartialCount--;
696 if (mPartialCount == 0) {
697 if (LOG_PARTIAL_WL) EventLog.writeEvent(LOG_POWER_PARTIAL_WAKE_STATE, 0, wl.tag);
698 Power.releaseWakeLock(PARTIAL_NAME);
699 }
Mike Lockwoodbc706a02009-07-27 13:50:57 -0700700 } else if ((wl.flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) {
701 mProximityCount--;
702 if (mProximityCount == 0) {
703 disableProximityLockLocked();
704 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800705 }
706 // Unlink the lock from the binder.
707 wl.binder.unlinkToDeath(wl, 0);
708 releaseUid = wl.uid;
709 releaseName = wl.tag;
710 releaseType = wl.monitorType;
711
712 if (releaseType >= 0) {
713 long origId = Binder.clearCallingIdentity();
714 try {
715 mBatteryStats.noteStopWakelock(releaseUid, releaseName, releaseType);
716 } catch (RemoteException e) {
717 // Ignore
718 } finally {
719 Binder.restoreCallingIdentity(origId);
720 }
721 }
722 }
723
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800724 private class PokeLock implements IBinder.DeathRecipient
725 {
726 PokeLock(int p, IBinder b, String t) {
727 super();
728 this.pokey = p;
729 this.binder = b;
730 this.tag = t;
731 try {
732 b.linkToDeath(this, 0);
733 } catch (RemoteException e) {
734 binderDied();
735 }
736 }
737 public void binderDied() {
738 setPokeLock(0, this.binder, this.tag);
739 }
740 int pokey;
741 IBinder binder;
742 String tag;
743 boolean awakeOnSet;
744 }
745
746 public void setPokeLock(int pokey, IBinder token, String tag) {
747 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
748 if (token == null) {
749 Log.e(TAG, "setPokeLock got null token for tag='" + tag + "'");
750 return;
751 }
752
753 if ((pokey & POKE_LOCK_TIMEOUT_MASK) == POKE_LOCK_TIMEOUT_MASK) {
754 throw new IllegalArgumentException("setPokeLock can't have both POKE_LOCK_SHORT_TIMEOUT"
755 + " and POKE_LOCK_MEDIUM_TIMEOUT");
756 }
757
758 synchronized (mLocks) {
759 if (pokey != 0) {
760 PokeLock p = mPokeLocks.get(token);
761 int oldPokey = 0;
762 if (p != null) {
763 oldPokey = p.pokey;
764 p.pokey = pokey;
765 } else {
766 p = new PokeLock(pokey, token, tag);
767 mPokeLocks.put(token, p);
768 }
769 int oldTimeout = oldPokey & POKE_LOCK_TIMEOUT_MASK;
770 int newTimeout = pokey & POKE_LOCK_TIMEOUT_MASK;
771 if (((mPowerState & SCREEN_ON_BIT) == 0) && (oldTimeout != newTimeout)) {
772 p.awakeOnSet = true;
773 }
774 } else {
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -0700775 PokeLock rLock = mPokeLocks.remove(token);
776 if (rLock != null) {
777 token.unlinkToDeath(rLock, 0);
778 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800779 }
780
781 int oldPokey = mPokey;
782 int cumulative = 0;
783 boolean oldAwakeOnSet = mPokeAwakeOnSet;
784 boolean awakeOnSet = false;
785 for (PokeLock p: mPokeLocks.values()) {
786 cumulative |= p.pokey;
787 if (p.awakeOnSet) {
788 awakeOnSet = true;
789 }
790 }
791 mPokey = cumulative;
792 mPokeAwakeOnSet = awakeOnSet;
793
794 int oldCumulativeTimeout = oldPokey & POKE_LOCK_TIMEOUT_MASK;
795 int newCumulativeTimeout = pokey & POKE_LOCK_TIMEOUT_MASK;
796
797 if (oldCumulativeTimeout != newCumulativeTimeout) {
798 setScreenOffTimeoutsLocked();
799 // reset the countdown timer, but use the existing nextState so it doesn't
800 // change anything
801 setTimeoutLocked(SystemClock.uptimeMillis(), mTimeoutTask.nextState);
802 }
803 }
804 }
805
806 private static String lockType(int type)
807 {
808 switch (type)
809 {
810 case PowerManager.FULL_WAKE_LOCK:
David Brown251faa62009-08-02 22:04:36 -0700811 return "FULL_WAKE_LOCK ";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800812 case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
David Brown251faa62009-08-02 22:04:36 -0700813 return "SCREEN_BRIGHT_WAKE_LOCK ";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800814 case PowerManager.SCREEN_DIM_WAKE_LOCK:
David Brown251faa62009-08-02 22:04:36 -0700815 return "SCREEN_DIM_WAKE_LOCK ";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800816 case PowerManager.PARTIAL_WAKE_LOCK:
David Brown251faa62009-08-02 22:04:36 -0700817 return "PARTIAL_WAKE_LOCK ";
818 case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
819 return "PROXIMITY_SCREEN_OFF_WAKE_LOCK";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800820 default:
David Brown251faa62009-08-02 22:04:36 -0700821 return "??? ";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800822 }
823 }
824
825 private static String dumpPowerState(int state) {
826 return (((state & KEYBOARD_BRIGHT_BIT) != 0)
827 ? "KEYBOARD_BRIGHT_BIT " : "")
828 + (((state & SCREEN_BRIGHT_BIT) != 0)
829 ? "SCREEN_BRIGHT_BIT " : "")
830 + (((state & SCREEN_ON_BIT) != 0)
831 ? "SCREEN_ON_BIT " : "")
832 + (((state & BATTERY_LOW_BIT) != 0)
833 ? "BATTERY_LOW_BIT " : "");
834 }
835
836 @Override
837 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
838 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
839 != PackageManager.PERMISSION_GRANTED) {
840 pw.println("Permission Denial: can't dump PowerManager from from pid="
841 + Binder.getCallingPid()
842 + ", uid=" + Binder.getCallingUid());
843 return;
844 }
845
846 long now = SystemClock.uptimeMillis();
847
848 pw.println("Power Manager State:");
849 pw.println(" mIsPowered=" + mIsPowered
850 + " mPowerState=" + mPowerState
851 + " mScreenOffTime=" + (SystemClock.elapsedRealtime()-mScreenOffTime)
852 + " ms");
853 pw.println(" mPartialCount=" + mPartialCount);
854 pw.println(" mWakeLockState=" + dumpPowerState(mWakeLockState));
855 pw.println(" mUserState=" + dumpPowerState(mUserState));
856 pw.println(" mPowerState=" + dumpPowerState(mPowerState));
857 pw.println(" mLocks.gather=" + dumpPowerState(mLocks.gatherState()));
858 pw.println(" mNextTimeout=" + mNextTimeout + " now=" + now
859 + " " + ((mNextTimeout-now)/1000) + "s from now");
860 pw.println(" mDimScreen=" + mDimScreen
861 + " mStayOnConditions=" + mStayOnConditions);
862 pw.println(" mOffBecauseOfUser=" + mOffBecauseOfUser
863 + " mUserState=" + mUserState);
Joe Onorato128e7292009-03-24 18:41:31 -0700864 pw.println(" mBroadcastQueue={" + mBroadcastQueue[0] + ',' + mBroadcastQueue[1]
865 + ',' + mBroadcastQueue[2] + "}");
866 pw.println(" mBroadcastWhy={" + mBroadcastWhy[0] + ',' + mBroadcastWhy[1]
867 + ',' + mBroadcastWhy[2] + "}");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868 pw.println(" mPokey=" + mPokey + " mPokeAwakeonSet=" + mPokeAwakeOnSet);
869 pw.println(" mKeyboardVisible=" + mKeyboardVisible
870 + " mUserActivityAllowed=" + mUserActivityAllowed);
871 pw.println(" mKeylightDelay=" + mKeylightDelay + " mDimDelay=" + mDimDelay
872 + " mScreenOffDelay=" + mScreenOffDelay);
873 pw.println(" mPreventScreenOn=" + mPreventScreenOn
874 + " mScreenBrightnessOverride=" + mScreenBrightnessOverride);
875 pw.println(" mTotalDelaySetting=" + mTotalDelaySetting);
876 pw.println(" mBroadcastWakeLock=" + mBroadcastWakeLock);
877 pw.println(" mStayOnWhilePluggedInScreenDimLock=" + mStayOnWhilePluggedInScreenDimLock);
878 pw.println(" mStayOnWhilePluggedInPartialLock=" + mStayOnWhilePluggedInPartialLock);
879 pw.println(" mPreventScreenOnPartialLock=" + mPreventScreenOnPartialLock);
Mike Lockwoodd7786b42009-10-15 17:09:16 -0700880 pw.println(" mProximitySensorActive=" + mProximitySensorActive);
881 pw.println(" mLightSensorEnabled=" + mLightSensorEnabled);
882 pw.println(" mLightSensorValue=" + mLightSensorValue);
883 pw.println(" mLightSensorPendingValue=" + mLightSensorPendingValue);
884 pw.println(" mHasHardwareAutoBrightness=" + mHasHardwareAutoBrightness);
885 pw.println(" mAutoBrightessEnabled=" + mAutoBrightessEnabled);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800886 mScreenBrightness.dump(pw, " mScreenBrightness: ");
887 mKeyboardBrightness.dump(pw, " mKeyboardBrightness: ");
888 mButtonBrightness.dump(pw, " mButtonBrightness: ");
889
890 int N = mLocks.size();
891 pw.println();
892 pw.println("mLocks.size=" + N + ":");
893 for (int i=0; i<N; i++) {
894 WakeLock wl = mLocks.get(i);
895 String type = lockType(wl.flags & LOCK_MASK);
896 String acquireCausesWakeup = "";
897 if ((wl.flags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0) {
898 acquireCausesWakeup = "ACQUIRE_CAUSES_WAKEUP ";
899 }
900 String activated = "";
901 if (wl.activated) {
902 activated = " activated";
903 }
904 pw.println(" " + type + " '" + wl.tag + "'" + acquireCausesWakeup
905 + activated + " (minState=" + wl.minState + ")");
906 }
907
908 pw.println();
909 pw.println("mPokeLocks.size=" + mPokeLocks.size() + ":");
910 for (PokeLock p: mPokeLocks.values()) {
911 pw.println(" poke lock '" + p.tag + "':"
912 + ((p.pokey & POKE_LOCK_IGNORE_CHEEK_EVENTS) != 0
913 ? " POKE_LOCK_IGNORE_CHEEK_EVENTS" : "")
Joe Onoratoe68ffcb2009-03-24 19:11:13 -0700914 + ((p.pokey & POKE_LOCK_IGNORE_TOUCH_AND_CHEEK_EVENTS) != 0
915 ? " POKE_LOCK_IGNORE_TOUCH_AND_CHEEK_EVENTS" : "")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800916 + ((p.pokey & POKE_LOCK_SHORT_TIMEOUT) != 0
917 ? " POKE_LOCK_SHORT_TIMEOUT" : "")
918 + ((p.pokey & POKE_LOCK_MEDIUM_TIMEOUT) != 0
919 ? " POKE_LOCK_MEDIUM_TIMEOUT" : ""));
920 }
921
922 pw.println();
923 }
924
925 private void setTimeoutLocked(long now, int nextState)
926 {
927 if (mDoneBooting) {
928 mHandler.removeCallbacks(mTimeoutTask);
929 mTimeoutTask.nextState = nextState;
930 long when = now;
931 switch (nextState)
932 {
933 case SCREEN_BRIGHT:
934 when += mKeylightDelay;
935 break;
936 case SCREEN_DIM:
937 if (mDimDelay >= 0) {
938 when += mDimDelay;
939 break;
940 } else {
941 Log.w(TAG, "mDimDelay=" + mDimDelay + " while trying to dim");
942 }
943 case SCREEN_OFF:
944 synchronized (mLocks) {
945 when += mScreenOffDelay;
946 }
947 break;
948 }
949 if (mSpew) {
950 Log.d(TAG, "setTimeoutLocked now=" + now + " nextState=" + nextState
951 + " when=" + when);
952 }
953 mHandler.postAtTime(mTimeoutTask, when);
954 mNextTimeout = when; // for debugging
955 }
956 }
957
958 private void cancelTimerLocked()
959 {
960 mHandler.removeCallbacks(mTimeoutTask);
961 mTimeoutTask.nextState = -1;
962 }
963
964 private class TimeoutTask implements Runnable
965 {
966 int nextState; // access should be synchronized on mLocks
967 public void run()
968 {
969 synchronized (mLocks) {
970 if (mSpew) {
971 Log.d(TAG, "user activity timeout timed out nextState=" + this.nextState);
972 }
973
974 if (nextState == -1) {
975 return;
976 }
977
978 mUserState = this.nextState;
979 setPowerState(this.nextState | mWakeLockState);
980
981 long now = SystemClock.uptimeMillis();
982
983 switch (this.nextState)
984 {
985 case SCREEN_BRIGHT:
986 if (mDimDelay >= 0) {
987 setTimeoutLocked(now, SCREEN_DIM);
988 break;
989 }
990 case SCREEN_DIM:
991 setTimeoutLocked(now, SCREEN_OFF);
992 break;
993 }
994 }
995 }
996 }
997
998 private void sendNotificationLocked(boolean on, int why)
999 {
Joe Onorato64c62ba2009-03-24 20:13:57 -07001000 if (!on) {
1001 mStillNeedSleepNotification = false;
1002 }
1003
Joe Onorato128e7292009-03-24 18:41:31 -07001004 // Add to the queue.
1005 int index = 0;
1006 while (mBroadcastQueue[index] != -1) {
1007 index++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001008 }
Joe Onorato128e7292009-03-24 18:41:31 -07001009 mBroadcastQueue[index] = on ? 1 : 0;
1010 mBroadcastWhy[index] = why;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001011
Joe Onorato128e7292009-03-24 18:41:31 -07001012 // If we added it position 2, then there is a pair that can be stripped.
1013 // If we added it position 1 and we're turning the screen off, we can strip
1014 // the pair and do nothing, because the screen is already off, and therefore
1015 // keyguard has already been enabled.
1016 // However, if we added it at position 1 and we're turning it on, then position
1017 // 0 was to turn it off, and we can't strip that, because keyguard needs to come
1018 // on, so have to run the queue then.
1019 if (index == 2) {
1020 // Also, while we're collapsing them, if it's going to be an "off," and one
1021 // is off because of user, then use that, regardless of whether it's the first
1022 // or second one.
1023 if (!on && why == WindowManagerPolicy.OFF_BECAUSE_OF_USER) {
1024 mBroadcastWhy[0] = WindowManagerPolicy.OFF_BECAUSE_OF_USER;
1025 }
1026 mBroadcastQueue[0] = on ? 1 : 0;
1027 mBroadcastQueue[1] = -1;
1028 mBroadcastQueue[2] = -1;
1029 index = 0;
1030 }
1031 if (index == 1 && !on) {
1032 mBroadcastQueue[0] = -1;
1033 mBroadcastQueue[1] = -1;
1034 index = -1;
1035 // The wake lock was being held, but we're not actually going to do any
1036 // broadcasts, so release the wake lock.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001037 EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_STOP, 1, mBroadcastWakeLock.mCount);
1038 mBroadcastWakeLock.release();
Joe Onorato128e7292009-03-24 18:41:31 -07001039 }
1040
1041 // Now send the message.
1042 if (index >= 0) {
1043 // Acquire the broadcast wake lock before changing the power
1044 // state. It will be release after the broadcast is sent.
1045 // We always increment the ref count for each notification in the queue
1046 // and always decrement when that notification is handled.
1047 mBroadcastWakeLock.acquire();
1048 EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_SEND, mBroadcastWakeLock.mCount);
1049 mHandler.post(mNotificationTask);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001050 }
1051 }
1052
1053 private Runnable mNotificationTask = new Runnable()
1054 {
1055 public void run()
1056 {
Joe Onorato128e7292009-03-24 18:41:31 -07001057 while (true) {
1058 int value;
1059 int why;
1060 WindowManagerPolicy policy;
1061 synchronized (mLocks) {
1062 value = mBroadcastQueue[0];
1063 why = mBroadcastWhy[0];
1064 for (int i=0; i<2; i++) {
1065 mBroadcastQueue[i] = mBroadcastQueue[i+1];
1066 mBroadcastWhy[i] = mBroadcastWhy[i+1];
1067 }
1068 policy = getPolicyLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001069 }
Joe Onorato128e7292009-03-24 18:41:31 -07001070 if (value == 1) {
1071 mScreenOnStart = SystemClock.uptimeMillis();
1072
1073 policy.screenTurnedOn();
1074 try {
1075 ActivityManagerNative.getDefault().wakingUp();
1076 } catch (RemoteException e) {
1077 // ignore it
1078 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001079
Joe Onorato128e7292009-03-24 18:41:31 -07001080 if (mSpew) {
1081 Log.d(TAG, "mBroadcastWakeLock=" + mBroadcastWakeLock);
1082 }
1083 if (mContext != null && ActivityManagerNative.isSystemReady()) {
1084 mContext.sendOrderedBroadcast(mScreenOnIntent, null,
1085 mScreenOnBroadcastDone, mHandler, 0, null, null);
1086 } else {
1087 synchronized (mLocks) {
1088 EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_STOP, 2,
1089 mBroadcastWakeLock.mCount);
1090 mBroadcastWakeLock.release();
1091 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001092 }
1093 }
Joe Onorato128e7292009-03-24 18:41:31 -07001094 else if (value == 0) {
1095 mScreenOffStart = SystemClock.uptimeMillis();
1096
1097 policy.screenTurnedOff(why);
1098 try {
1099 ActivityManagerNative.getDefault().goingToSleep();
1100 } catch (RemoteException e) {
1101 // ignore it.
1102 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001103
Joe Onorato128e7292009-03-24 18:41:31 -07001104 if (mContext != null && ActivityManagerNative.isSystemReady()) {
1105 mContext.sendOrderedBroadcast(mScreenOffIntent, null,
1106 mScreenOffBroadcastDone, mHandler, 0, null, null);
1107 } else {
1108 synchronized (mLocks) {
1109 EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_STOP, 3,
1110 mBroadcastWakeLock.mCount);
1111 mBroadcastWakeLock.release();
1112 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001113 }
1114 }
Joe Onorato128e7292009-03-24 18:41:31 -07001115 else {
1116 // If we're in this case, then this handler is running for a previous
1117 // paired transaction. mBroadcastWakeLock will already have been released.
1118 break;
1119 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001120 }
1121 }
1122 };
1123
1124 long mScreenOnStart;
1125 private BroadcastReceiver mScreenOnBroadcastDone = new BroadcastReceiver() {
1126 public void onReceive(Context context, Intent intent) {
1127 synchronized (mLocks) {
1128 EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_DONE, 1,
1129 SystemClock.uptimeMillis() - mScreenOnStart, mBroadcastWakeLock.mCount);
1130 mBroadcastWakeLock.release();
1131 }
1132 }
1133 };
1134
1135 long mScreenOffStart;
1136 private BroadcastReceiver mScreenOffBroadcastDone = new BroadcastReceiver() {
1137 public void onReceive(Context context, Intent intent) {
1138 synchronized (mLocks) {
1139 EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_DONE, 0,
1140 SystemClock.uptimeMillis() - mScreenOffStart, mBroadcastWakeLock.mCount);
1141 mBroadcastWakeLock.release();
1142 }
1143 }
1144 };
1145
1146 void logPointerUpEvent() {
1147 if (LOG_TOUCH_DOWNS) {
1148 mTotalTouchDownTime += SystemClock.elapsedRealtime() - mLastTouchDown;
1149 mLastTouchDown = 0;
1150 }
1151 }
1152
1153 void logPointerDownEvent() {
1154 if (LOG_TOUCH_DOWNS) {
1155 // If we are not already timing a down/up sequence
1156 if (mLastTouchDown == 0) {
1157 mLastTouchDown = SystemClock.elapsedRealtime();
1158 mTouchCycles++;
1159 }
1160 }
1161 }
1162
1163 /**
1164 * Prevents the screen from turning on even if it *should* turn on due
1165 * to a subsequent full wake lock being acquired.
1166 * <p>
1167 * This is a temporary hack that allows an activity to "cover up" any
1168 * display glitches that happen during the activity's startup
1169 * sequence. (Specifically, this API was added to work around a
1170 * cosmetic bug in the "incoming call" sequence, where the lock screen
1171 * would flicker briefly before the incoming call UI became visible.)
1172 * TODO: There ought to be a more elegant way of doing this,
1173 * probably by having the PowerManager and ActivityManager
1174 * work together to let apps specify that the screen on/off
1175 * state should be synchronized with the Activity lifecycle.
1176 * <p>
1177 * Note that calling preventScreenOn(true) will NOT turn the screen
1178 * off if it's currently on. (This API only affects *future*
1179 * acquisitions of full wake locks.)
1180 * But calling preventScreenOn(false) WILL turn the screen on if
1181 * it's currently off because of a prior preventScreenOn(true) call.
1182 * <p>
1183 * Any call to preventScreenOn(true) MUST be followed promptly by a call
1184 * to preventScreenOn(false). In fact, if the preventScreenOn(false)
1185 * call doesn't occur within 5 seconds, we'll turn the screen back on
1186 * ourselves (and log a warning about it); this prevents a buggy app
1187 * from disabling the screen forever.)
1188 * <p>
1189 * TODO: this feature should really be controlled by a new type of poke
1190 * lock (rather than an IPowerManager call).
1191 */
1192 public void preventScreenOn(boolean prevent) {
1193 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
1194
1195 synchronized (mLocks) {
1196 if (prevent) {
1197 // First of all, grab a partial wake lock to
1198 // make sure the CPU stays on during the entire
1199 // preventScreenOn(true) -> preventScreenOn(false) sequence.
1200 mPreventScreenOnPartialLock.acquire();
1201
1202 // Post a forceReenableScreen() call (for 5 seconds in the
1203 // future) to make sure the matching preventScreenOn(false) call
1204 // has happened by then.
1205 mHandler.removeCallbacks(mForceReenableScreenTask);
1206 mHandler.postDelayed(mForceReenableScreenTask, 5000);
1207
1208 // Finally, set the flag that prevents the screen from turning on.
1209 // (Below, in setPowerState(), we'll check mPreventScreenOn and
Mike Lockwood8738e0c2009-10-04 08:44:47 -04001210 // we *won't* call setScreenStateLocked(true) if it's set.)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001211 mPreventScreenOn = true;
1212 } else {
1213 // (Re)enable the screen.
1214 mPreventScreenOn = false;
1215
1216 // We're "undoing" a the prior preventScreenOn(true) call, so we
1217 // no longer need the 5-second safeguard.
1218 mHandler.removeCallbacks(mForceReenableScreenTask);
1219
1220 // Forcibly turn on the screen if it's supposed to be on. (This
1221 // handles the case where the screen is currently off because of
1222 // a prior preventScreenOn(true) call.)
1223 if ((mPowerState & SCREEN_ON_BIT) != 0) {
1224 if (mSpew) {
1225 Log.d(TAG,
1226 "preventScreenOn: turning on after a prior preventScreenOn(true)!");
1227 }
Mike Lockwood8738e0c2009-10-04 08:44:47 -04001228 int err = setScreenStateLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001229 if (err != 0) {
Mike Lockwood8738e0c2009-10-04 08:44:47 -04001230 Log.w(TAG, "preventScreenOn: error from setScreenStateLocked(): " + err);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001231 }
1232 }
1233
1234 // Release the partial wake lock that we held during the
1235 // preventScreenOn(true) -> preventScreenOn(false) sequence.
1236 mPreventScreenOnPartialLock.release();
1237 }
1238 }
1239 }
1240
1241 public void setScreenBrightnessOverride(int brightness) {
1242 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
1243
1244 synchronized (mLocks) {
1245 if (mScreenBrightnessOverride != brightness) {
1246 mScreenBrightnessOverride = brightness;
1247 updateLightsLocked(mPowerState, SCREEN_ON_BIT);
1248 }
1249 }
1250 }
1251
1252 /**
1253 * Sanity-check that gets called 5 seconds after any call to
1254 * preventScreenOn(true). This ensures that the original call
1255 * is followed promptly by a call to preventScreenOn(false).
1256 */
1257 private void forceReenableScreen() {
1258 // We shouldn't get here at all if mPreventScreenOn is false, since
1259 // we should have already removed any existing
1260 // mForceReenableScreenTask messages...
1261 if (!mPreventScreenOn) {
1262 Log.w(TAG, "forceReenableScreen: mPreventScreenOn is false, nothing to do");
1263 return;
1264 }
1265
1266 // Uh oh. It's been 5 seconds since a call to
1267 // preventScreenOn(true) and we haven't re-enabled the screen yet.
1268 // This means the app that called preventScreenOn(true) is either
1269 // slow (i.e. it took more than 5 seconds to call preventScreenOn(false)),
1270 // or buggy (i.e. it forgot to call preventScreenOn(false), or
1271 // crashed before doing so.)
1272
1273 // Log a warning, and forcibly turn the screen back on.
1274 Log.w(TAG, "App called preventScreenOn(true) but didn't promptly reenable the screen! "
1275 + "Forcing the screen back on...");
1276 preventScreenOn(false);
1277 }
1278
1279 private Runnable mForceReenableScreenTask = new Runnable() {
1280 public void run() {
1281 forceReenableScreen();
1282 }
1283 };
1284
Mike Lockwood8738e0c2009-10-04 08:44:47 -04001285 private int setScreenStateLocked(boolean on) {
1286 int err = Power.setScreenState(on);
1287 if (err == 0) {
1288 enableLightSensor(on && mAutoBrightessEnabled);
Mike Lockwoodd7786b42009-10-15 17:09:16 -07001289 if (!on) {
1290 // make sure button and key backlights are off too
1291 mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS, 0);
1292 mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD, 0);
Mike Lockwood6c97fca2009-10-20 08:10:00 -04001293 // clear current value so we will update based on the new conditions
1294 // when the sensor is reenabled.
1295 mLightSensorValue = -1;
Mike Lockwoodd7786b42009-10-15 17:09:16 -07001296 }
Mike Lockwood8738e0c2009-10-04 08:44:47 -04001297 }
1298 return err;
1299 }
1300
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001301 private void setPowerState(int state)
1302 {
1303 setPowerState(state, false, false);
1304 }
1305
1306 private void setPowerState(int newState, boolean noChangeLights, boolean becauseOfUser)
1307 {
1308 synchronized (mLocks) {
1309 int err;
1310
1311 if (mSpew) {
1312 Log.d(TAG, "setPowerState: mPowerState=0x" + Integer.toHexString(mPowerState)
1313 + " newState=0x" + Integer.toHexString(newState)
1314 + " noChangeLights=" + noChangeLights);
1315 }
1316
1317 if (noChangeLights) {
1318 newState = (newState & ~LIGHTS_MASK) | (mPowerState & LIGHTS_MASK);
1319 }
Mike Lockwood36fc3022009-08-25 16:49:06 -07001320 if (mProximitySensorActive) {
1321 // don't turn on the screen when the proximity sensor lock is held
1322 newState = (newState & ~SCREEN_BRIGHT);
1323 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001324
1325 if (batteryIsLow()) {
1326 newState |= BATTERY_LOW_BIT;
1327 } else {
1328 newState &= ~BATTERY_LOW_BIT;
1329 }
1330 if (newState == mPowerState) {
1331 return;
1332 }
1333
Mike Lockwood6c97fca2009-10-20 08:10:00 -04001334 if (!mDoneBooting && !mAutoBrightessEnabled) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001335 newState |= ALL_BRIGHT;
1336 }
1337
1338 boolean oldScreenOn = (mPowerState & SCREEN_ON_BIT) != 0;
1339 boolean newScreenOn = (newState & SCREEN_ON_BIT) != 0;
1340
1341 if (mSpew) {
1342 Log.d(TAG, "setPowerState: mPowerState=" + mPowerState
1343 + " newState=" + newState + " noChangeLights=" + noChangeLights);
1344 Log.d(TAG, " oldKeyboardBright=" + ((mPowerState & KEYBOARD_BRIGHT_BIT) != 0)
1345 + " newKeyboardBright=" + ((newState & KEYBOARD_BRIGHT_BIT) != 0));
1346 Log.d(TAG, " oldScreenBright=" + ((mPowerState & SCREEN_BRIGHT_BIT) != 0)
1347 + " newScreenBright=" + ((newState & SCREEN_BRIGHT_BIT) != 0));
1348 Log.d(TAG, " oldButtonBright=" + ((mPowerState & BUTTON_BRIGHT_BIT) != 0)
1349 + " newButtonBright=" + ((newState & BUTTON_BRIGHT_BIT) != 0));
1350 Log.d(TAG, " oldScreenOn=" + oldScreenOn
1351 + " newScreenOn=" + newScreenOn);
1352 Log.d(TAG, " oldBatteryLow=" + ((mPowerState & BATTERY_LOW_BIT) != 0)
1353 + " newBatteryLow=" + ((newState & BATTERY_LOW_BIT) != 0));
1354 }
1355
1356 if (mPowerState != newState) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001357 updateLightsLocked(newState, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001358 mPowerState = (mPowerState & ~LIGHTS_MASK) | (newState & LIGHTS_MASK);
1359 }
1360
1361 if (oldScreenOn != newScreenOn) {
1362 if (newScreenOn) {
Joe Onorato128e7292009-03-24 18:41:31 -07001363 // When the user presses the power button, we need to always send out the
1364 // notification that it's going to sleep so the keyguard goes on. But
1365 // we can't do that until the screen fades out, so we don't show the keyguard
1366 // too early.
1367 if (mStillNeedSleepNotification) {
1368 sendNotificationLocked(false, WindowManagerPolicy.OFF_BECAUSE_OF_USER);
1369 }
1370
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001371 // Turn on the screen UNLESS there was a prior
1372 // preventScreenOn(true) request. (Note that the lifetime
1373 // of a single preventScreenOn() request is limited to 5
1374 // seconds to prevent a buggy app from disabling the
1375 // screen forever; see forceReenableScreen().)
1376 boolean reallyTurnScreenOn = true;
1377 if (mSpew) {
1378 Log.d(TAG, "- turning screen on... mPreventScreenOn = "
1379 + mPreventScreenOn);
1380 }
1381
1382 if (mPreventScreenOn) {
1383 if (mSpew) {
1384 Log.d(TAG, "- PREVENTING screen from really turning on!");
1385 }
1386 reallyTurnScreenOn = false;
1387 }
1388 if (reallyTurnScreenOn) {
Mike Lockwood8738e0c2009-10-04 08:44:47 -04001389 err = setScreenStateLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001390 long identity = Binder.clearCallingIdentity();
1391 try {
Dianne Hackborn617f8772009-03-31 15:04:46 -07001392 mBatteryStats.noteScreenBrightness(
1393 getPreferredBrightness());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001394 mBatteryStats.noteScreenOn();
1395 } catch (RemoteException e) {
1396 Log.w(TAG, "RemoteException calling noteScreenOn on BatteryStatsService", e);
1397 } finally {
1398 Binder.restoreCallingIdentity(identity);
1399 }
1400 } else {
Mike Lockwood8738e0c2009-10-04 08:44:47 -04001401 setScreenStateLocked(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001402 // But continue as if we really did turn the screen on...
1403 err = 0;
1404 }
1405
1406 mScreenOnStartTime = SystemClock.elapsedRealtime();
1407 mLastTouchDown = 0;
1408 mTotalTouchDownTime = 0;
1409 mTouchCycles = 0;
1410 EventLog.writeEvent(LOG_POWER_SCREEN_STATE, 1, becauseOfUser ? 1 : 0,
1411 mTotalTouchDownTime, mTouchCycles);
1412 if (err == 0) {
1413 mPowerState |= SCREEN_ON_BIT;
1414 sendNotificationLocked(true, -1);
1415 }
1416 } else {
1417 mScreenOffTime = SystemClock.elapsedRealtime();
1418 long identity = Binder.clearCallingIdentity();
1419 try {
1420 mBatteryStats.noteScreenOff();
1421 } catch (RemoteException e) {
1422 Log.w(TAG, "RemoteException calling noteScreenOff on BatteryStatsService", e);
1423 } finally {
1424 Binder.restoreCallingIdentity(identity);
1425 }
1426 mPowerState &= ~SCREEN_ON_BIT;
1427 if (!mScreenBrightness.animating) {
Joe Onorato128e7292009-03-24 18:41:31 -07001428 err = screenOffFinishedAnimatingLocked(becauseOfUser);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001429 } else {
1430 mOffBecauseOfUser = becauseOfUser;
1431 err = 0;
1432 mLastTouchDown = 0;
1433 }
1434 }
1435 }
1436 }
1437 }
1438
Joe Onorato128e7292009-03-24 18:41:31 -07001439 private int screenOffFinishedAnimatingLocked(boolean becauseOfUser) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001440 // I don't think we need to check the current state here because all of these
1441 // Power.setScreenState and sendNotificationLocked can both handle being
1442 // called multiple times in the same state. -joeo
1443 EventLog.writeEvent(LOG_POWER_SCREEN_STATE, 0, becauseOfUser ? 1 : 0,
1444 mTotalTouchDownTime, mTouchCycles);
1445 mLastTouchDown = 0;
Mike Lockwood8738e0c2009-10-04 08:44:47 -04001446 int err = setScreenStateLocked(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001447 if (mScreenOnStartTime != 0) {
1448 mScreenOnTime += SystemClock.elapsedRealtime() - mScreenOnStartTime;
1449 mScreenOnStartTime = 0;
1450 }
1451 if (err == 0) {
1452 int why = becauseOfUser
1453 ? WindowManagerPolicy.OFF_BECAUSE_OF_USER
1454 : WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT;
1455 sendNotificationLocked(false, why);
1456 }
1457 return err;
1458 }
1459
1460 private boolean batteryIsLow() {
1461 return (!mIsPowered &&
1462 mBatteryService.getBatteryLevel() <= Power.LOW_BATTERY_THRESHOLD);
1463 }
1464
The Android Open Source Project10592532009-03-18 17:39:46 -07001465 private void updateLightsLocked(int newState, int forceState) {
Dianne Hackborn9ed4a4b2009-03-25 17:10:37 -07001466 final int oldState = mPowerState;
1467 final int realDifference = (newState ^ oldState);
1468 final int difference = realDifference | forceState;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001469 if (difference == 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001470 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001471 }
1472
1473 int offMask = 0;
1474 int dimMask = 0;
1475 int onMask = 0;
1476
1477 int preferredBrightness = getPreferredBrightness();
1478 boolean startAnimation = false;
1479
1480 if ((difference & KEYBOARD_BRIGHT_BIT) != 0) {
1481 if (ANIMATE_KEYBOARD_LIGHTS) {
1482 if ((newState & KEYBOARD_BRIGHT_BIT) == 0) {
1483 mKeyboardBrightness.setTargetLocked(Power.BRIGHTNESS_OFF,
Joe Onorato128e7292009-03-24 18:41:31 -07001484 ANIM_STEPS, INITIAL_KEYBOARD_BRIGHTNESS,
1485 preferredBrightness);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001486 } else {
1487 mKeyboardBrightness.setTargetLocked(preferredBrightness,
Joe Onorato128e7292009-03-24 18:41:31 -07001488 ANIM_STEPS, INITIAL_KEYBOARD_BRIGHTNESS,
1489 Power.BRIGHTNESS_OFF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001490 }
1491 startAnimation = true;
1492 } else {
1493 if ((newState & KEYBOARD_BRIGHT_BIT) == 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001494 offMask |= KEYBOARD_BRIGHT_BIT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001495 } else {
The Android Open Source Project10592532009-03-18 17:39:46 -07001496 onMask |= KEYBOARD_BRIGHT_BIT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001497 }
1498 }
1499 }
1500
1501 if ((difference & BUTTON_BRIGHT_BIT) != 0) {
1502 if (ANIMATE_BUTTON_LIGHTS) {
1503 if ((newState & BUTTON_BRIGHT_BIT) == 0) {
1504 mButtonBrightness.setTargetLocked(Power.BRIGHTNESS_OFF,
Joe Onorato128e7292009-03-24 18:41:31 -07001505 ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
1506 preferredBrightness);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001507 } else {
1508 mButtonBrightness.setTargetLocked(preferredBrightness,
Joe Onorato128e7292009-03-24 18:41:31 -07001509 ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
1510 Power.BRIGHTNESS_OFF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001511 }
1512 startAnimation = true;
1513 } else {
1514 if ((newState & BUTTON_BRIGHT_BIT) == 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001515 offMask |= BUTTON_BRIGHT_BIT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001516 } else {
The Android Open Source Project10592532009-03-18 17:39:46 -07001517 onMask |= BUTTON_BRIGHT_BIT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001518 }
1519 }
1520 }
1521
1522 if ((difference & (SCREEN_ON_BIT | SCREEN_BRIGHT_BIT)) != 0) {
1523 if (ANIMATE_SCREEN_LIGHTS) {
Dianne Hackborn9ed4a4b2009-03-25 17:10:37 -07001524 int nominalCurrentValue = -1;
1525 // If there was an actual difference in the light state, then
1526 // figure out the "ideal" current value based on the previous
1527 // state. Otherwise, this is a change due to the brightness
1528 // override, so we want to animate from whatever the current
1529 // value is.
1530 if ((realDifference & (SCREEN_ON_BIT | SCREEN_BRIGHT_BIT)) != 0) {
1531 switch (oldState & (SCREEN_BRIGHT_BIT|SCREEN_ON_BIT)) {
1532 case SCREEN_BRIGHT_BIT | SCREEN_ON_BIT:
1533 nominalCurrentValue = preferredBrightness;
1534 break;
1535 case SCREEN_ON_BIT:
1536 nominalCurrentValue = Power.BRIGHTNESS_DIM;
1537 break;
1538 case 0:
1539 nominalCurrentValue = Power.BRIGHTNESS_OFF;
1540 break;
1541 case SCREEN_BRIGHT_BIT:
1542 default:
1543 // not possible
1544 nominalCurrentValue = (int)mScreenBrightness.curValue;
1545 break;
1546 }
Joe Onorato128e7292009-03-24 18:41:31 -07001547 }
Dianne Hackborn617f8772009-03-31 15:04:46 -07001548 int brightness = preferredBrightness;
1549 int steps = ANIM_STEPS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001550 if ((newState & SCREEN_BRIGHT_BIT) == 0) {
1551 // dim or turn off backlight, depending on if the screen is on
1552 // the scale is because the brightness ramp isn't linear and this biases
1553 // it so the later parts take longer.
1554 final float scale = 1.5f;
1555 float ratio = (((float)Power.BRIGHTNESS_DIM)/preferredBrightness);
1556 if (ratio > 1.0f) ratio = 1.0f;
1557 if ((newState & SCREEN_ON_BIT) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001558 if ((oldState & SCREEN_BRIGHT_BIT) != 0) {
1559 // was bright
1560 steps = ANIM_STEPS;
1561 } else {
1562 // was dim
1563 steps = (int)(ANIM_STEPS*ratio*scale);
1564 }
Dianne Hackborn617f8772009-03-31 15:04:46 -07001565 brightness = Power.BRIGHTNESS_OFF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001566 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001567 if ((oldState & SCREEN_ON_BIT) != 0) {
1568 // was bright
1569 steps = (int)(ANIM_STEPS*(1.0f-ratio)*scale);
1570 } else {
1571 // was dim
1572 steps = (int)(ANIM_STEPS*ratio);
1573 }
1574 if (mStayOnConditions != 0 && mBatteryService.isPowered(mStayOnConditions)) {
1575 // If the "stay on while plugged in" option is
1576 // turned on, then the screen will often not
1577 // automatically turn off while plugged in. To
1578 // still have a sense of when it is inactive, we
1579 // will then count going dim as turning off.
1580 mScreenOffTime = SystemClock.elapsedRealtime();
1581 }
Dianne Hackborn617f8772009-03-31 15:04:46 -07001582 brightness = Power.BRIGHTNESS_DIM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001583 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001584 }
Dianne Hackborn617f8772009-03-31 15:04:46 -07001585 long identity = Binder.clearCallingIdentity();
1586 try {
1587 mBatteryStats.noteScreenBrightness(brightness);
1588 } catch (RemoteException e) {
1589 // Nothing interesting to do.
1590 } finally {
1591 Binder.restoreCallingIdentity(identity);
1592 }
Dianne Hackbornaa80b602009-10-09 17:38:26 -07001593 if (mScreenBrightness.setTargetLocked(brightness,
1594 steps, INITIAL_SCREEN_BRIGHTNESS, nominalCurrentValue)) {
1595 startAnimation = true;
1596 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001597 } else {
1598 if ((newState & SCREEN_BRIGHT_BIT) == 0) {
1599 // dim or turn off backlight, depending on if the screen is on
1600 if ((newState & SCREEN_ON_BIT) == 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001601 offMask |= SCREEN_BRIGHT_BIT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001602 } else {
The Android Open Source Project10592532009-03-18 17:39:46 -07001603 dimMask |= SCREEN_BRIGHT_BIT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001604 }
1605 } else {
The Android Open Source Project10592532009-03-18 17:39:46 -07001606 onMask |= SCREEN_BRIGHT_BIT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001607 }
1608 }
1609 }
1610
1611 if (startAnimation) {
1612 if (mSpew) {
1613 Log.i(TAG, "Scheduling light animator!");
1614 }
1615 mHandler.removeCallbacks(mLightAnimator);
1616 mHandler.post(mLightAnimator);
1617 }
1618
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001619 if (offMask != 0) {
1620 //Log.i(TAG, "Setting brightess off: " + offMask);
The Android Open Source Project10592532009-03-18 17:39:46 -07001621 setLightBrightness(offMask, Power.BRIGHTNESS_OFF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001622 }
1623 if (dimMask != 0) {
1624 int brightness = Power.BRIGHTNESS_DIM;
1625 if ((newState & BATTERY_LOW_BIT) != 0 &&
1626 brightness > Power.BRIGHTNESS_LOW_BATTERY) {
1627 brightness = Power.BRIGHTNESS_LOW_BATTERY;
1628 }
1629 //Log.i(TAG, "Setting brightess dim " + brightness + ": " + offMask);
The Android Open Source Project10592532009-03-18 17:39:46 -07001630 setLightBrightness(dimMask, brightness);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001631 }
1632 if (onMask != 0) {
1633 int brightness = getPreferredBrightness();
1634 if ((newState & BATTERY_LOW_BIT) != 0 &&
1635 brightness > Power.BRIGHTNESS_LOW_BATTERY) {
1636 brightness = Power.BRIGHTNESS_LOW_BATTERY;
1637 }
1638 //Log.i(TAG, "Setting brightess on " + brightness + ": " + onMask);
The Android Open Source Project10592532009-03-18 17:39:46 -07001639 setLightBrightness(onMask, brightness);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001640 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001641 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001642
The Android Open Source Project10592532009-03-18 17:39:46 -07001643 private void setLightBrightness(int mask, int value) {
1644 if ((mask & SCREEN_BRIGHT_BIT) != 0) {
1645 mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BACKLIGHT, value);
1646 }
1647 if ((mask & BUTTON_BRIGHT_BIT) != 0) {
1648 mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS, value);
1649 }
1650 if ((mask & KEYBOARD_BRIGHT_BIT) != 0) {
1651 mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD, value);
1652 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001653 }
1654
1655 class BrightnessState {
1656 final int mask;
1657
1658 boolean initialized;
1659 int targetValue;
1660 float curValue;
1661 float delta;
1662 boolean animating;
1663
1664 BrightnessState(int m) {
1665 mask = m;
1666 }
1667
1668 public void dump(PrintWriter pw, String prefix) {
1669 pw.println(prefix + "animating=" + animating
1670 + " targetValue=" + targetValue
1671 + " curValue=" + curValue
1672 + " delta=" + delta);
1673 }
1674
Dianne Hackbornaa80b602009-10-09 17:38:26 -07001675 boolean setTargetLocked(int target, int stepsToTarget, int initialValue,
Joe Onorato128e7292009-03-24 18:41:31 -07001676 int nominalCurrentValue) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001677 if (!initialized) {
1678 initialized = true;
1679 curValue = (float)initialValue;
Dianne Hackbornaa80b602009-10-09 17:38:26 -07001680 } else if (targetValue == target) {
1681 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001682 }
1683 targetValue = target;
Dianne Hackborn9ed4a4b2009-03-25 17:10:37 -07001684 delta = (targetValue -
1685 (nominalCurrentValue >= 0 ? nominalCurrentValue : curValue))
1686 / stepsToTarget;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001687 if (mSpew) {
Joe Onorato128e7292009-03-24 18:41:31 -07001688 String noticeMe = nominalCurrentValue == curValue ? "" : " ******************";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001689 Log.i(TAG, "Setting target " + mask + ": cur=" + curValue
Joe Onorato128e7292009-03-24 18:41:31 -07001690 + " target=" + targetValue + " delta=" + delta
1691 + " nominalCurrentValue=" + nominalCurrentValue
1692 + noticeMe);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001693 }
1694 animating = true;
Dianne Hackbornaa80b602009-10-09 17:38:26 -07001695 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001696 }
1697
1698 boolean stepLocked() {
1699 if (!animating) return false;
1700 if (false && mSpew) {
1701 Log.i(TAG, "Step target " + mask + ": cur=" + curValue
1702 + " target=" + targetValue + " delta=" + delta);
1703 }
1704 curValue += delta;
1705 int curIntValue = (int)curValue;
1706 boolean more = true;
1707 if (delta == 0) {
Dianne Hackborn9ed4a4b2009-03-25 17:10:37 -07001708 curValue = curIntValue = targetValue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001709 more = false;
1710 } else if (delta > 0) {
1711 if (curIntValue >= targetValue) {
1712 curValue = curIntValue = targetValue;
1713 more = false;
1714 }
1715 } else {
1716 if (curIntValue <= targetValue) {
1717 curValue = curIntValue = targetValue;
1718 more = false;
1719 }
1720 }
1721 //Log.i(TAG, "Animating brightess " + curIntValue + ": " + mask);
The Android Open Source Project10592532009-03-18 17:39:46 -07001722 setLightBrightness(mask, curIntValue);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001723 animating = more;
1724 if (!more) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001725 if (mask == SCREEN_BRIGHT_BIT && curIntValue == Power.BRIGHTNESS_OFF) {
Joe Onorato128e7292009-03-24 18:41:31 -07001726 screenOffFinishedAnimatingLocked(mOffBecauseOfUser);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001727 }
1728 }
1729 return more;
1730 }
1731 }
1732
1733 private class LightAnimator implements Runnable {
1734 public void run() {
1735 synchronized (mLocks) {
1736 long now = SystemClock.uptimeMillis();
1737 boolean more = mScreenBrightness.stepLocked();
1738 if (mKeyboardBrightness.stepLocked()) {
1739 more = true;
1740 }
1741 if (mButtonBrightness.stepLocked()) {
1742 more = true;
1743 }
1744 if (more) {
1745 mHandler.postAtTime(mLightAnimator, now+(1000/60));
1746 }
1747 }
1748 }
1749 }
1750
1751 private int getPreferredBrightness() {
1752 try {
1753 if (mScreenBrightnessOverride >= 0) {
1754 return mScreenBrightnessOverride;
Mike Lockwoodd7786b42009-10-15 17:09:16 -07001755 } else if (mLightSensorBrightness >= 0) {
1756 return mLightSensorBrightness;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001757 }
1758 final int brightness = Settings.System.getInt(mContext.getContentResolver(),
1759 SCREEN_BRIGHTNESS);
1760 // Don't let applications turn the screen all the way off
1761 return Math.max(brightness, Power.BRIGHTNESS_DIM);
1762 } catch (SettingNotFoundException snfe) {
1763 return Power.BRIGHTNESS_ON;
1764 }
1765 }
1766
1767 boolean screenIsOn() {
1768 synchronized (mLocks) {
1769 return (mPowerState & SCREEN_ON_BIT) != 0;
1770 }
1771 }
1772
1773 boolean screenIsBright() {
1774 synchronized (mLocks) {
1775 return (mPowerState & SCREEN_BRIGHT) == SCREEN_BRIGHT;
1776 }
1777 }
1778
Mike Lockwood200b30b2009-09-20 00:23:59 -04001779 private void forceUserActivityLocked() {
1780 boolean savedActivityAllowed = mUserActivityAllowed;
1781 mUserActivityAllowed = true;
1782 userActivity(SystemClock.uptimeMillis(), false);
1783 mUserActivityAllowed = savedActivityAllowed;
1784 }
1785
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001786 public void userActivityWithForce(long time, boolean noChangeLights, boolean force) {
1787 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
1788 userActivity(time, noChangeLights, OTHER_EVENT, force);
1789 }
1790
1791 public void userActivity(long time, boolean noChangeLights) {
1792 userActivity(time, noChangeLights, OTHER_EVENT, false);
1793 }
1794
1795 public void userActivity(long time, boolean noChangeLights, int eventType) {
1796 userActivity(time, noChangeLights, eventType, false);
1797 }
1798
1799 public void userActivity(long time, boolean noChangeLights, int eventType, boolean force) {
1800 //mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
1801
1802 if (((mPokey & POKE_LOCK_IGNORE_CHEEK_EVENTS) != 0)
Joe Onoratoe68ffcb2009-03-24 19:11:13 -07001803 && (eventType == CHEEK_EVENT || eventType == TOUCH_EVENT)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001804 if (false) {
Joe Onoratoe68ffcb2009-03-24 19:11:13 -07001805 Log.d(TAG, "dropping cheek or short event mPokey=0x" + Integer.toHexString(mPokey));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001806 }
1807 return;
1808 }
1809
Joe Onoratoe68ffcb2009-03-24 19:11:13 -07001810 if (((mPokey & POKE_LOCK_IGNORE_TOUCH_AND_CHEEK_EVENTS) != 0)
1811 && (eventType == TOUCH_EVENT || eventType == TOUCH_UP_EVENT
1812 || eventType == LONG_TOUCH_EVENT || eventType == CHEEK_EVENT)) {
1813 if (false) {
1814 Log.d(TAG, "dropping touch mPokey=0x" + Integer.toHexString(mPokey));
1815 }
1816 return;
1817 }
1818
1819
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001820 if (false) {
1821 if (((mPokey & POKE_LOCK_IGNORE_CHEEK_EVENTS) != 0)) {
1822 Log.d(TAG, "userActivity !!!");//, new RuntimeException());
1823 } else {
1824 Log.d(TAG, "mPokey=0x" + Integer.toHexString(mPokey));
1825 }
1826 }
1827
1828 synchronized (mLocks) {
1829 if (mSpew) {
1830 Log.d(TAG, "userActivity mLastEventTime=" + mLastEventTime + " time=" + time
1831 + " mUserActivityAllowed=" + mUserActivityAllowed
1832 + " mUserState=0x" + Integer.toHexString(mUserState)
Mike Lockwood36fc3022009-08-25 16:49:06 -07001833 + " mWakeLockState=0x" + Integer.toHexString(mWakeLockState)
1834 + " mProximitySensorActive=" + mProximitySensorActive
1835 + " force=" + force);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001836 }
1837 if (mLastEventTime <= time || force) {
1838 mLastEventTime = time;
Mike Lockwood36fc3022009-08-25 16:49:06 -07001839 if ((mUserActivityAllowed && !mProximitySensorActive) || force) {
Mike Lockwoodd7786b42009-10-15 17:09:16 -07001840 // Only turn on button backlights if a button was pressed
1841 // and auto brightness is disabled
1842 if (eventType == BUTTON_EVENT && !mAutoBrightessEnabled) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001843 mUserState = (mKeyboardVisible ? ALL_BRIGHT : SCREEN_BUTTON_BRIGHT);
1844 } else {
1845 // don't clear button/keyboard backlights when the screen is touched.
1846 mUserState |= SCREEN_BRIGHT;
1847 }
1848
Dianne Hackborn617f8772009-03-31 15:04:46 -07001849 int uid = Binder.getCallingUid();
1850 long ident = Binder.clearCallingIdentity();
1851 try {
1852 mBatteryStats.noteUserActivity(uid, eventType);
1853 } catch (RemoteException e) {
1854 // Ignore
1855 } finally {
1856 Binder.restoreCallingIdentity(ident);
1857 }
1858
Michael Chane96440f2009-05-06 10:27:36 -07001859 mWakeLockState = mLocks.reactivateScreenLocksLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001860 setPowerState(mUserState | mWakeLockState, noChangeLights, true);
1861 setTimeoutLocked(time, SCREEN_BRIGHT);
1862 }
1863 }
1864 }
1865 }
1866
Mike Lockwoodd7786b42009-10-15 17:09:16 -07001867 private int getAutoBrightnessValue(int sensorValue, int[] values) {
1868 try {
1869 int i;
1870 for (i = 0; i < mAutoBrightnessLevels.length; i++) {
1871 if (sensorValue < mAutoBrightnessLevels[i]) {
1872 break;
1873 }
1874 }
1875 return values[i];
1876 } catch (Exception e) {
1877 // guard against null pointer or index out of bounds errors
1878 Log.e(TAG, "getAutoBrightnessValue", e);
1879 return 255;
1880 }
1881 }
1882
1883 private Runnable mAutoBrightnessTask = new Runnable() {
1884 public void run() {
Mike Lockwoodfa68ab42009-10-20 11:08:49 -04001885 synchronized (mLocks) {
1886 int value = (int)mLightSensorPendingValue;
1887 if (value >= 0) {
1888 mLightSensorPendingValue = -1;
1889 lightSensorChangedLocked(value);
1890 }
Mike Lockwoodd7786b42009-10-15 17:09:16 -07001891 }
1892 }
1893 };
1894
1895 private void lightSensorChangedLocked(int value) {
Mike Lockwood8738e0c2009-10-04 08:44:47 -04001896 if (mDebugLightSensor) {
1897 Log.d(TAG, "lightSensorChangedLocked " + value);
1898 }
Mike Lockwoodd7786b42009-10-15 17:09:16 -07001899
1900 if (mLightSensorValue != value) {
1901 mLightSensorValue = value;
1902 if ((mPowerState & BATTERY_LOW_BIT) == 0) {
1903 int lcdValue = getAutoBrightnessValue(value, mLcdBacklightValues);
1904 int buttonValue = getAutoBrightnessValue(value, mButtonBacklightValues);
1905 int keyboardValue = getAutoBrightnessValue(value, mKeyboardBacklightValues);
1906 mLightSensorBrightness = lcdValue;
1907
1908 if (mDebugLightSensor) {
1909 Log.d(TAG, "lcdValue " + lcdValue);
1910 Log.d(TAG, "buttonValue " + buttonValue);
1911 Log.d(TAG, "keyboardValue " + keyboardValue);
1912 }
1913
1914 if (mScreenBrightnessOverride < 0) {
1915 mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BACKLIGHT,
1916 lcdValue);
1917 }
1918 mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS,
1919 buttonValue);
1920 mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD,
1921 keyboardValue);
1922
1923 // update our animation state
1924 if (ANIMATE_SCREEN_LIGHTS) {
1925 mScreenBrightness.curValue = lcdValue;
1926 mScreenBrightness.animating = false;
1927 }
1928 if (ANIMATE_BUTTON_LIGHTS) {
1929 mButtonBrightness.curValue = buttonValue;
1930 mButtonBrightness.animating = false;
1931 }
1932 if (ANIMATE_KEYBOARD_LIGHTS) {
1933 mKeyboardBrightness.curValue = keyboardValue;
1934 mKeyboardBrightness.animating = false;
1935 }
1936 }
1937 }
Mike Lockwood8738e0c2009-10-04 08:44:47 -04001938 }
1939
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001940 /**
1941 * The user requested that we go to sleep (probably with the power button).
1942 * This overrides all wake locks that are held.
1943 */
1944 public void goToSleep(long time)
1945 {
1946 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
1947 synchronized (mLocks) {
1948 goToSleepLocked(time);
1949 }
1950 }
1951
1952 /**
1953 * Returns the time the screen has been on since boot, in millis.
1954 * @return screen on time
1955 */
1956 public long getScreenOnTime() {
1957 synchronized (mLocks) {
1958 if (mScreenOnStartTime == 0) {
1959 return mScreenOnTime;
1960 } else {
1961 return SystemClock.elapsedRealtime() - mScreenOnStartTime + mScreenOnTime;
1962 }
1963 }
1964 }
1965
1966 private void goToSleepLocked(long time) {
1967
1968 if (mLastEventTime <= time) {
1969 mLastEventTime = time;
1970 // cancel all of the wake locks
1971 mWakeLockState = SCREEN_OFF;
1972 int N = mLocks.size();
1973 int numCleared = 0;
1974 for (int i=0; i<N; i++) {
1975 WakeLock wl = mLocks.get(i);
1976 if (isScreenLock(wl.flags)) {
1977 mLocks.get(i).activated = false;
1978 numCleared++;
1979 }
1980 }
1981 EventLog.writeEvent(LOG_POWER_SLEEP_REQUESTED, numCleared);
Joe Onorato128e7292009-03-24 18:41:31 -07001982 mStillNeedSleepNotification = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001983 mUserState = SCREEN_OFF;
1984 setPowerState(SCREEN_OFF, false, true);
1985 cancelTimerLocked();
1986 }
1987 }
1988
1989 public long timeSinceScreenOn() {
1990 synchronized (mLocks) {
1991 if ((mPowerState & SCREEN_ON_BIT) != 0) {
1992 return 0;
1993 }
1994 return SystemClock.elapsedRealtime() - mScreenOffTime;
1995 }
1996 }
1997
1998 public void setKeyboardVisibility(boolean visible) {
Mike Lockwooda625b382009-09-12 17:36:03 -07001999 synchronized (mLocks) {
2000 if (mSpew) {
2001 Log.d(TAG, "setKeyboardVisibility: " + visible);
2002 }
2003 mKeyboardVisible = visible;
Dianne Hackbornfe2bddf2009-09-20 15:21:10 -07002004 // don't signal user activity if the screen is off; other code
2005 // will take care of turning on due to a true change to the lid
2006 // switch and synchronized with the lock screen.
2007 if ((mPowerState & SCREEN_ON_BIT) != 0) {
Mike Lockwooda625b382009-09-12 17:36:03 -07002008 userActivity(SystemClock.uptimeMillis(), false, BUTTON_EVENT, true);
2009 }
2010 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002011 }
2012
2013 /**
2014 * When the keyguard is up, it manages the power state, and userActivity doesn't do anything.
2015 */
2016 public void enableUserActivity(boolean enabled) {
2017 synchronized (mLocks) {
2018 mUserActivityAllowed = enabled;
2019 mLastEventTime = SystemClock.uptimeMillis(); // we might need to pass this in
2020 }
2021 }
2022
Mike Lockwooddc3494e2009-10-14 21:17:09 -07002023 private void setScreenBrightnessMode(int mode) {
2024 mAutoBrightessEnabled = (mode == SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
Mike Lockwoodd7786b42009-10-15 17:09:16 -07002025 // reset computed brightness
2026 mLightSensorBrightness = -1;
Mike Lockwooddc3494e2009-10-14 21:17:09 -07002027
2028 if (mHasHardwareAutoBrightness) {
2029 // When setting auto-brightness, must reset the brightness afterwards
2030 mHardware.setAutoBrightness_UNCHECKED(mAutoBrightessEnabled);
2031 setBacklightBrightness((int)mScreenBrightness.curValue);
2032 } else {
Mike Lockwood8738e0c2009-10-04 08:44:47 -04002033 enableLightSensor(screenIsOn() && mAutoBrightessEnabled);
Mike Lockwooddc3494e2009-10-14 21:17:09 -07002034 }
2035 }
2036
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002037 /** Sets the screen off timeouts:
2038 * mKeylightDelay
2039 * mDimDelay
2040 * mScreenOffDelay
2041 * */
2042 private void setScreenOffTimeoutsLocked() {
2043 if ((mPokey & POKE_LOCK_SHORT_TIMEOUT) != 0) {
2044 mKeylightDelay = mShortKeylightDelay; // Configurable via Gservices
2045 mDimDelay = -1;
2046 mScreenOffDelay = 0;
2047 } else if ((mPokey & POKE_LOCK_MEDIUM_TIMEOUT) != 0) {
2048 mKeylightDelay = MEDIUM_KEYLIGHT_DELAY;
2049 mDimDelay = -1;
2050 mScreenOffDelay = 0;
2051 } else {
2052 int totalDelay = mTotalDelaySetting;
2053 mKeylightDelay = LONG_KEYLIGHT_DELAY;
2054 if (totalDelay < 0) {
2055 mScreenOffDelay = Integer.MAX_VALUE;
2056 } else if (mKeylightDelay < totalDelay) {
2057 // subtract the time that the keylight delay. This will give us the
2058 // remainder of the time that we need to sleep to get the accurate
2059 // screen off timeout.
2060 mScreenOffDelay = totalDelay - mKeylightDelay;
2061 } else {
2062 mScreenOffDelay = 0;
2063 }
2064 if (mDimScreen && totalDelay >= (LONG_KEYLIGHT_DELAY + LONG_DIM_TIME)) {
2065 mDimDelay = mScreenOffDelay - LONG_DIM_TIME;
2066 mScreenOffDelay = LONG_DIM_TIME;
2067 } else {
2068 mDimDelay = -1;
2069 }
2070 }
2071 if (mSpew) {
2072 Log.d(TAG, "setScreenOffTimeouts mKeylightDelay=" + mKeylightDelay
2073 + " mDimDelay=" + mDimDelay + " mScreenOffDelay=" + mScreenOffDelay
2074 + " mDimScreen=" + mDimScreen);
2075 }
2076 }
2077
2078 /**
2079 * Refreshes cached Gservices settings. Called once on startup, and
2080 * on subsequent Settings.Gservices.CHANGED_ACTION broadcasts (see
2081 * GservicesChangedReceiver).
2082 */
2083 private void updateGservicesValues() {
2084 mShortKeylightDelay = Settings.Gservices.getInt(
2085 mContext.getContentResolver(),
2086 Settings.Gservices.SHORT_KEYLIGHT_DELAY_MS,
2087 SHORT_KEYLIGHT_DELAY_DEFAULT);
2088 // Log.i(TAG, "updateGservicesValues(): mShortKeylightDelay now " + mShortKeylightDelay);
2089 }
2090
2091 /**
2092 * Receiver for the Gservices.CHANGED_ACTION broadcast intent,
2093 * which tells us we need to refresh our cached Gservices settings.
2094 */
2095 private class GservicesChangedReceiver extends BroadcastReceiver {
2096 @Override
2097 public void onReceive(Context context, Intent intent) {
2098 // Log.i(TAG, "GservicesChangedReceiver.onReceive(): " + intent);
2099 updateGservicesValues();
2100 }
2101 }
2102
2103 private class LockList extends ArrayList<WakeLock>
2104 {
2105 void addLock(WakeLock wl)
2106 {
2107 int index = getIndex(wl.binder);
2108 if (index < 0) {
2109 this.add(wl);
2110 }
2111 }
2112
2113 WakeLock removeLock(IBinder binder)
2114 {
2115 int index = getIndex(binder);
2116 if (index >= 0) {
2117 return this.remove(index);
2118 } else {
2119 return null;
2120 }
2121 }
2122
2123 int getIndex(IBinder binder)
2124 {
2125 int N = this.size();
2126 for (int i=0; i<N; i++) {
2127 if (this.get(i).binder == binder) {
2128 return i;
2129 }
2130 }
2131 return -1;
2132 }
2133
2134 int gatherState()
2135 {
2136 int result = 0;
2137 int N = this.size();
2138 for (int i=0; i<N; i++) {
2139 WakeLock wl = this.get(i);
2140 if (wl.activated) {
2141 if (isScreenLock(wl.flags)) {
2142 result |= wl.minState;
2143 }
2144 }
2145 }
2146 return result;
2147 }
Michael Chane96440f2009-05-06 10:27:36 -07002148
2149 int reactivateScreenLocksLocked()
2150 {
2151 int result = 0;
2152 int N = this.size();
2153 for (int i=0; i<N; i++) {
2154 WakeLock wl = this.get(i);
2155 if (isScreenLock(wl.flags)) {
2156 wl.activated = true;
2157 result |= wl.minState;
2158 }
2159 }
2160 return result;
2161 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002162 }
2163
2164 void setPolicy(WindowManagerPolicy p) {
2165 synchronized (mLocks) {
2166 mPolicy = p;
2167 mLocks.notifyAll();
2168 }
2169 }
2170
2171 WindowManagerPolicy getPolicyLocked() {
2172 while (mPolicy == null || !mDoneBooting) {
2173 try {
2174 mLocks.wait();
2175 } catch (InterruptedException e) {
2176 // Ignore
2177 }
2178 }
2179 return mPolicy;
2180 }
2181
2182 void systemReady() {
Mike Lockwood8738e0c2009-10-04 08:44:47 -04002183 mSensorManager = new SensorManager(mHandlerThread.getLooper());
2184 mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
2185 // don't bother with the light sensor if auto brightness is handled in hardware
2186 if (!mHasHardwareAutoBrightness) {
2187 mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
2188 enableLightSensor(mAutoBrightessEnabled);
2189 }
2190
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002191 synchronized (mLocks) {
2192 Log.d(TAG, "system ready!");
2193 mDoneBooting = true;
Dianne Hackborn617f8772009-03-31 15:04:46 -07002194 long identity = Binder.clearCallingIdentity();
2195 try {
2196 mBatteryStats.noteScreenBrightness(getPreferredBrightness());
2197 mBatteryStats.noteScreenOn();
2198 } catch (RemoteException e) {
2199 // Nothing interesting to do.
2200 } finally {
2201 Binder.restoreCallingIdentity(identity);
2202 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002203 userActivity(SystemClock.uptimeMillis(), false, BUTTON_EVENT, true);
2204 updateWakeLockLocked();
2205 mLocks.notifyAll();
2206 }
2207 }
2208
2209 public void monitor() {
2210 synchronized (mLocks) { }
2211 }
Mike Lockwoodbc706a02009-07-27 13:50:57 -07002212
2213 public int getSupportedWakeLockFlags() {
2214 int result = PowerManager.PARTIAL_WAKE_LOCK
2215 | PowerManager.FULL_WAKE_LOCK
2216 | PowerManager.SCREEN_DIM_WAKE_LOCK;
2217
Mike Lockwoodbc706a02009-07-27 13:50:57 -07002218 if (mProximitySensor != null) {
2219 result |= PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK;
2220 }
2221
2222 return result;
2223 }
2224
Mike Lockwood237a2992009-09-15 14:42:16 -04002225 public void setBacklightBrightness(int brightness) {
2226 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
2227 // Don't let applications turn the screen all the way off
2228 brightness = Math.max(brightness, Power.BRIGHTNESS_DIM);
2229 mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BACKLIGHT, brightness);
2230 mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD, brightness);
2231 mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS, brightness);
2232 long identity = Binder.clearCallingIdentity();
2233 try {
2234 mBatteryStats.noteScreenBrightness(brightness);
2235 } catch (RemoteException e) {
2236 Log.w(TAG, "RemoteException calling noteScreenBrightness on BatteryStatsService", e);
2237 } finally {
2238 Binder.restoreCallingIdentity(identity);
2239 }
2240
2241 // update our animation state
2242 if (ANIMATE_SCREEN_LIGHTS) {
2243 mScreenBrightness.curValue = brightness;
2244 mScreenBrightness.animating = false;
2245 }
2246 if (ANIMATE_KEYBOARD_LIGHTS) {
2247 mKeyboardBrightness.curValue = brightness;
2248 mKeyboardBrightness.animating = false;
2249 }
2250 if (ANIMATE_BUTTON_LIGHTS) {
2251 mButtonBrightness.curValue = brightness;
2252 mButtonBrightness.animating = false;
2253 }
2254 }
2255
Mike Lockwoodbc706a02009-07-27 13:50:57 -07002256 private void enableProximityLockLocked() {
Mike Lockwood36fc3022009-08-25 16:49:06 -07002257 if (mSpew) {
2258 Log.d(TAG, "enableProximityLockLocked");
2259 }
Mike Lockwood8738e0c2009-10-04 08:44:47 -04002260 mSensorManager.registerListener(mProximityListener, mProximitySensor,
2261 SensorManager.SENSOR_DELAY_NORMAL);
Mike Lockwoodbc706a02009-07-27 13:50:57 -07002262 }
2263
2264 private void disableProximityLockLocked() {
Mike Lockwood36fc3022009-08-25 16:49:06 -07002265 if (mSpew) {
2266 Log.d(TAG, "disableProximityLockLocked");
2267 }
Mike Lockwood8738e0c2009-10-04 08:44:47 -04002268 mSensorManager.unregisterListener(mProximityListener);
Mike Lockwood200b30b2009-09-20 00:23:59 -04002269 synchronized (mLocks) {
2270 if (mProximitySensorActive) {
2271 mProximitySensorActive = false;
2272 forceUserActivityLocked();
2273 }
2274 }
Mike Lockwoodbc706a02009-07-27 13:50:57 -07002275 }
2276
Mike Lockwood8738e0c2009-10-04 08:44:47 -04002277 private void enableLightSensor(boolean enable) {
2278 if (mDebugLightSensor) {
2279 Log.d(TAG, "enableLightSensor " + enable);
2280 }
2281 if (mSensorManager != null && mLightSensorEnabled != enable) {
2282 mLightSensorEnabled = enable;
2283 if (enable) {
2284 mSensorManager.registerListener(mLightListener, mLightSensor,
2285 SensorManager.SENSOR_DELAY_NORMAL);
Mike Lockwood36fc3022009-08-25 16:49:06 -07002286 } else {
Mike Lockwood8738e0c2009-10-04 08:44:47 -04002287 mSensorManager.unregisterListener(mLightListener);
Mike Lockwood6c97fca2009-10-20 08:10:00 -04002288 mHandler.removeCallbacks(mAutoBrightnessTask);
Mike Lockwood06952d92009-08-13 16:05:38 -04002289 }
Mike Lockwoodbc706a02009-07-27 13:50:57 -07002290 }
2291 }
2292
Mike Lockwood8738e0c2009-10-04 08:44:47 -04002293 SensorEventListener mProximityListener = new SensorEventListener() {
2294 public void onSensorChanged(SensorEvent event) {
2295 long milliseconds = event.timestamp / 1000000;
2296 synchronized (mLocks) {
2297 float distance = event.values[0];
2298 // compare against getMaximumRange to support sensors that only return 0 or 1
2299 if (distance >= 0.0 && distance < PROXIMITY_THRESHOLD &&
2300 distance < mProximitySensor.getMaximumRange()) {
2301 if (mSpew) {
2302 Log.d(TAG, "onSensorChanged: proximity active, distance: " + distance);
2303 }
2304 goToSleepLocked(milliseconds);
2305 mProximitySensorActive = true;
2306 } else {
2307 // proximity sensor negative events trigger as user activity.
2308 // temporarily set mUserActivityAllowed to true so this will work
2309 // even when the keyguard is on.
2310 if (mSpew) {
2311 Log.d(TAG, "onSensorChanged: proximity inactive, distance: " + distance);
2312 }
2313 mProximitySensorActive = false;
2314 forceUserActivityLocked();
2315 }
2316 }
2317 }
2318
2319 public void onAccuracyChanged(Sensor sensor, int accuracy) {
2320 // ignore
2321 }
2322 };
2323
2324 SensorEventListener mLightListener = new SensorEventListener() {
2325 public void onSensorChanged(SensorEvent event) {
2326 synchronized (mLocks) {
2327 int value = (int)event.values[0];
2328 if (mDebugLightSensor) {
2329 Log.d(TAG, "onSensorChanged: light value: " + value);
2330 }
Mike Lockwoodd7786b42009-10-15 17:09:16 -07002331 mHandler.removeCallbacks(mAutoBrightnessTask);
2332 if (mLightSensorValue != value) {
Mike Lockwood6c97fca2009-10-20 08:10:00 -04002333 if (mLightSensorValue == -1) {
2334 // process the value immediately
2335 lightSensorChangedLocked(value);
2336 } else {
2337 // delay processing to debounce the sensor
2338 mLightSensorPendingValue = value;
2339 mHandler.postDelayed(mAutoBrightnessTask, LIGHT_SENSOR_DELAY);
2340 }
Mike Lockwoodd7786b42009-10-15 17:09:16 -07002341 } else {
2342 mLightSensorPendingValue = -1;
2343 }
Mike Lockwood8738e0c2009-10-04 08:44:47 -04002344 }
2345 }
2346
2347 public void onAccuracyChanged(Sensor sensor, int accuracy) {
2348 // ignore
2349 }
2350 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002351}