bed30e1b6e
Adds stats for: - Number of raw user events that have happened in the system. - Number of times user activity has been reported, dividied by UID and type of activity. - Duration of screen brightness levels in 4 buckets. - Per-UID tracking of who has turned on Wifi and how long we can attribute it being on because of them. Original author: hackbod Merged from: //branches/cupcake/... Original author: android-build Merged from: //branches/donutburger/... Automated import of CL 143823
1990 lines
78 KiB
Java
1990 lines
78 KiB
Java
/*
|
|
* Copyright (C) 2007 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.android.server;
|
|
|
|
import com.android.internal.app.IBatteryStats;
|
|
import com.android.server.am.BatteryStatsService;
|
|
|
|
import android.app.ActivityManagerNative;
|
|
import android.app.IActivityManager;
|
|
import android.content.BroadcastReceiver;
|
|
import android.content.ContentQueryMap;
|
|
import android.content.ContentResolver;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.IntentFilter;
|
|
import android.content.pm.PackageManager;
|
|
import android.database.Cursor;
|
|
import android.os.BatteryStats;
|
|
import android.os.Binder;
|
|
import android.os.Handler;
|
|
import android.os.HandlerThread;
|
|
import android.os.IBinder;
|
|
import android.os.IPowerManager;
|
|
import android.os.LocalPowerManager;
|
|
import android.os.Power;
|
|
import android.os.PowerManager;
|
|
import android.os.Process;
|
|
import android.os.RemoteException;
|
|
import android.os.SystemClock;
|
|
import android.provider.Settings.SettingNotFoundException;
|
|
import android.provider.Settings;
|
|
import android.util.EventLog;
|
|
import android.util.Log;
|
|
import android.view.WindowManagerPolicy;
|
|
import static android.provider.Settings.System.DIM_SCREEN;
|
|
import static android.provider.Settings.System.SCREEN_BRIGHTNESS;
|
|
import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
|
|
import static android.provider.Settings.System.STAY_ON_WHILE_PLUGGED_IN;
|
|
|
|
import java.io.FileDescriptor;
|
|
import java.io.PrintWriter;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.Observable;
|
|
import java.util.Observer;
|
|
|
|
class PowerManagerService extends IPowerManager.Stub implements LocalPowerManager, Watchdog.Monitor {
|
|
|
|
private static final String TAG = "PowerManagerService";
|
|
static final String PARTIAL_NAME = "PowerManagerService";
|
|
|
|
private static final boolean LOG_PARTIAL_WL = false;
|
|
|
|
// Indicates whether touch-down cycles should be logged as part of the
|
|
// LOG_POWER_SCREEN_STATE log events
|
|
private static final boolean LOG_TOUCH_DOWNS = true;
|
|
|
|
private static final int LOCK_MASK = PowerManager.PARTIAL_WAKE_LOCK
|
|
| PowerManager.SCREEN_DIM_WAKE_LOCK
|
|
| PowerManager.SCREEN_BRIGHT_WAKE_LOCK
|
|
| PowerManager.FULL_WAKE_LOCK;
|
|
|
|
// time since last state: time since last event:
|
|
// The short keylight delay comes from Gservices; this is the default.
|
|
private static final int SHORT_KEYLIGHT_DELAY_DEFAULT = 6000; // t+6 sec
|
|
private static final int MEDIUM_KEYLIGHT_DELAY = 15000; // t+15 sec
|
|
private static final int LONG_KEYLIGHT_DELAY = 6000; // t+6 sec
|
|
private static final int LONG_DIM_TIME = 7000; // t+N-5 sec
|
|
|
|
// Cached Gservices settings; see updateGservicesValues()
|
|
private int mShortKeylightDelay = SHORT_KEYLIGHT_DELAY_DEFAULT;
|
|
|
|
// flags for setPowerState
|
|
private static final int SCREEN_ON_BIT = 0x00000001;
|
|
private static final int SCREEN_BRIGHT_BIT = 0x00000002;
|
|
private static final int BUTTON_BRIGHT_BIT = 0x00000004;
|
|
private static final int KEYBOARD_BRIGHT_BIT = 0x00000008;
|
|
private static final int BATTERY_LOW_BIT = 0x00000010;
|
|
|
|
// values for setPowerState
|
|
|
|
// SCREEN_OFF == everything off
|
|
private static final int SCREEN_OFF = 0x00000000;
|
|
|
|
// SCREEN_DIM == screen on, screen backlight dim
|
|
private static final int SCREEN_DIM = SCREEN_ON_BIT;
|
|
|
|
// SCREEN_BRIGHT == screen on, screen backlight bright
|
|
private static final int SCREEN_BRIGHT = SCREEN_ON_BIT | SCREEN_BRIGHT_BIT;
|
|
|
|
// SCREEN_BUTTON_BRIGHT == screen on, screen and button backlights bright
|
|
private static final int SCREEN_BUTTON_BRIGHT = SCREEN_BRIGHT | BUTTON_BRIGHT_BIT;
|
|
|
|
// SCREEN_BUTTON_BRIGHT == screen on, screen, button and keyboard backlights bright
|
|
private static final int ALL_BRIGHT = SCREEN_BUTTON_BRIGHT | KEYBOARD_BRIGHT_BIT;
|
|
|
|
// used for noChangeLights in setPowerState()
|
|
private static final int LIGHTS_MASK = SCREEN_BRIGHT_BIT | BUTTON_BRIGHT_BIT | KEYBOARD_BRIGHT_BIT;
|
|
|
|
static final boolean ANIMATE_SCREEN_LIGHTS = true;
|
|
static final boolean ANIMATE_BUTTON_LIGHTS = false;
|
|
static final boolean ANIMATE_KEYBOARD_LIGHTS = false;
|
|
|
|
static final int ANIM_STEPS = 60/4;
|
|
|
|
// These magic numbers are the initial state of the LEDs at boot. Ideally
|
|
// we should read them from the driver, but our current hardware returns 0
|
|
// for the initial value. Oops!
|
|
static final int INITIAL_SCREEN_BRIGHTNESS = 255;
|
|
static final int INITIAL_BUTTON_BRIGHTNESS = Power.BRIGHTNESS_OFF;
|
|
static final int INITIAL_KEYBOARD_BRIGHTNESS = Power.BRIGHTNESS_OFF;
|
|
|
|
static final int LOG_POWER_SLEEP_REQUESTED = 2724;
|
|
static final int LOG_POWER_SCREEN_BROADCAST_SEND = 2725;
|
|
static final int LOG_POWER_SCREEN_BROADCAST_DONE = 2726;
|
|
static final int LOG_POWER_SCREEN_BROADCAST_STOP = 2727;
|
|
static final int LOG_POWER_SCREEN_STATE = 2728;
|
|
static final int LOG_POWER_PARTIAL_WAKE_STATE = 2729;
|
|
|
|
private final int MY_UID;
|
|
|
|
private boolean mDoneBooting = false;
|
|
private int mStayOnConditions = 0;
|
|
private int[] mBroadcastQueue = new int[] { -1, -1, -1 };
|
|
private int[] mBroadcastWhy = new int[3];
|
|
private int mPartialCount = 0;
|
|
private int mPowerState;
|
|
private boolean mOffBecauseOfUser;
|
|
private int mUserState;
|
|
private boolean mKeyboardVisible = false;
|
|
private boolean mUserActivityAllowed = true;
|
|
private int mTotalDelaySetting;
|
|
private int mKeylightDelay;
|
|
private int mDimDelay;
|
|
private int mScreenOffDelay;
|
|
private int mWakeLockState;
|
|
private long mLastEventTime = 0;
|
|
private long mScreenOffTime;
|
|
private volatile WindowManagerPolicy mPolicy;
|
|
private final LockList mLocks = new LockList();
|
|
private Intent mScreenOffIntent;
|
|
private Intent mScreenOnIntent;
|
|
private HardwareService mHardware;
|
|
private Context mContext;
|
|
private UnsynchronizedWakeLock mBroadcastWakeLock;
|
|
private UnsynchronizedWakeLock mStayOnWhilePluggedInScreenDimLock;
|
|
private UnsynchronizedWakeLock mStayOnWhilePluggedInPartialLock;
|
|
private UnsynchronizedWakeLock mPreventScreenOnPartialLock;
|
|
private HandlerThread mHandlerThread;
|
|
private Handler mHandler;
|
|
private TimeoutTask mTimeoutTask = new TimeoutTask();
|
|
private LightAnimator mLightAnimator = new LightAnimator();
|
|
private final BrightnessState mScreenBrightness
|
|
= new BrightnessState(SCREEN_BRIGHT_BIT);
|
|
private final BrightnessState mKeyboardBrightness
|
|
= new BrightnessState(KEYBOARD_BRIGHT_BIT);
|
|
private final BrightnessState mButtonBrightness
|
|
= new BrightnessState(BUTTON_BRIGHT_BIT);
|
|
private boolean mStillNeedSleepNotification;
|
|
private boolean mIsPowered = false;
|
|
private IActivityManager mActivityService;
|
|
private IBatteryStats mBatteryStats;
|
|
private BatteryService mBatteryService;
|
|
private boolean mDimScreen = true;
|
|
private long mNextTimeout;
|
|
private volatile int mPokey = 0;
|
|
private volatile boolean mPokeAwakeOnSet = false;
|
|
private volatile boolean mInitComplete = false;
|
|
private HashMap<IBinder,PokeLock> mPokeLocks = new HashMap<IBinder,PokeLock>();
|
|
private long mScreenOnTime;
|
|
private long mScreenOnStartTime;
|
|
private boolean mPreventScreenOn;
|
|
private int mScreenBrightnessOverride = -1;
|
|
|
|
// Used when logging number and duration of touch-down cycles
|
|
private long mTotalTouchDownTime;
|
|
private long mLastTouchDown;
|
|
private int mTouchCycles;
|
|
|
|
// could be either static or controllable at runtime
|
|
private static final boolean mSpew = false;
|
|
|
|
/*
|
|
static PrintStream mLog;
|
|
static {
|
|
try {
|
|
mLog = new PrintStream("/data/power.log");
|
|
}
|
|
catch (FileNotFoundException e) {
|
|
android.util.Log.e(TAG, "Life is hard", e);
|
|
}
|
|
}
|
|
static class Log {
|
|
static void d(String tag, String s) {
|
|
mLog.println(s);
|
|
android.util.Log.d(tag, s);
|
|
}
|
|
static void i(String tag, String s) {
|
|
mLog.println(s);
|
|
android.util.Log.i(tag, s);
|
|
}
|
|
static void w(String tag, String s) {
|
|
mLog.println(s);
|
|
android.util.Log.w(tag, s);
|
|
}
|
|
static void e(String tag, String s) {
|
|
mLog.println(s);
|
|
android.util.Log.e(tag, s);
|
|
}
|
|
}
|
|
*/
|
|
|
|
/**
|
|
* This class works around a deadlock between the lock in PowerManager.WakeLock
|
|
* and our synchronizing on mLocks. PowerManager.WakeLock synchronizes on its
|
|
* mToken object so it can be accessed from any thread, but it calls into here
|
|
* with its lock held. This class is essentially a reimplementation of
|
|
* PowerManager.WakeLock, but without that extra synchronized block, because we'll
|
|
* only call it with our own locks held.
|
|
*/
|
|
private class UnsynchronizedWakeLock {
|
|
int mFlags;
|
|
String mTag;
|
|
IBinder mToken;
|
|
int mCount = 0;
|
|
boolean mRefCounted;
|
|
|
|
UnsynchronizedWakeLock(int flags, String tag, boolean refCounted) {
|
|
mFlags = flags;
|
|
mTag = tag;
|
|
mToken = new Binder();
|
|
mRefCounted = refCounted;
|
|
}
|
|
|
|
public void acquire() {
|
|
if (!mRefCounted || mCount++ == 0) {
|
|
long ident = Binder.clearCallingIdentity();
|
|
try {
|
|
PowerManagerService.this.acquireWakeLockLocked(mFlags, mToken,
|
|
MY_UID, mTag);
|
|
} finally {
|
|
Binder.restoreCallingIdentity(ident);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void release() {
|
|
if (!mRefCounted || --mCount == 0) {
|
|
PowerManagerService.this.releaseWakeLockLocked(mToken, false);
|
|
}
|
|
if (mCount < 0) {
|
|
throw new RuntimeException("WakeLock under-locked " + mTag);
|
|
}
|
|
}
|
|
|
|
public String toString() {
|
|
return "UnsynchronizedWakeLock(mFlags=0x" + Integer.toHexString(mFlags)
|
|
+ " mCount=" + mCount + ")";
|
|
}
|
|
}
|
|
|
|
private final class BatteryReceiver extends BroadcastReceiver {
|
|
@Override
|
|
public void onReceive(Context context, Intent intent) {
|
|
synchronized (mLocks) {
|
|
boolean wasPowered = mIsPowered;
|
|
mIsPowered = mBatteryService.isPowered();
|
|
|
|
if (mIsPowered != wasPowered) {
|
|
// update mStayOnWhilePluggedIn wake lock
|
|
updateWakeLockLocked();
|
|
|
|
// treat plugging and unplugging the devices as a user activity.
|
|
// users find it disconcerting when they unplug the device
|
|
// and it shuts off right away.
|
|
// temporarily set mUserActivityAllowed to true so this will work
|
|
// even when the keyguard is on.
|
|
synchronized (mLocks) {
|
|
boolean savedActivityAllowed = mUserActivityAllowed;
|
|
mUserActivityAllowed = true;
|
|
userActivity(SystemClock.uptimeMillis(), false);
|
|
mUserActivityAllowed = savedActivityAllowed;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set the setting that determines whether the device stays on when plugged in.
|
|
* The argument is a bit string, with each bit specifying a power source that,
|
|
* when the device is connected to that source, causes the device to stay on.
|
|
* See {@link android.os.BatteryManager} for the list of power sources that
|
|
* can be specified. Current values include {@link android.os.BatteryManager#BATTERY_PLUGGED_AC}
|
|
* and {@link android.os.BatteryManager#BATTERY_PLUGGED_USB}
|
|
* @param val an {@code int} containing the bits that specify which power sources
|
|
* should cause the device to stay on.
|
|
*/
|
|
public void setStayOnSetting(int val) {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SETTINGS, null);
|
|
Settings.System.putInt(mContext.getContentResolver(),
|
|
Settings.System.STAY_ON_WHILE_PLUGGED_IN, val);
|
|
}
|
|
|
|
private class SettingsObserver implements Observer {
|
|
private int getInt(String name) {
|
|
return mSettings.getValues(name).getAsInteger(Settings.System.VALUE);
|
|
}
|
|
|
|
public void update(Observable o, Object arg) {
|
|
synchronized (mLocks) {
|
|
// STAY_ON_WHILE_PLUGGED_IN
|
|
mStayOnConditions = getInt(STAY_ON_WHILE_PLUGGED_IN);
|
|
updateWakeLockLocked();
|
|
|
|
// SCREEN_OFF_TIMEOUT
|
|
mTotalDelaySetting = getInt(SCREEN_OFF_TIMEOUT);
|
|
|
|
// DIM_SCREEN
|
|
//mDimScreen = getInt(DIM_SCREEN) != 0;
|
|
|
|
// recalculate everything
|
|
setScreenOffTimeoutsLocked();
|
|
}
|
|
}
|
|
}
|
|
|
|
PowerManagerService()
|
|
{
|
|
// Hack to get our uid... should have a func for this.
|
|
long token = Binder.clearCallingIdentity();
|
|
MY_UID = Binder.getCallingUid();
|
|
Binder.restoreCallingIdentity(token);
|
|
|
|
// XXX remove this when the kernel doesn't timeout wake locks
|
|
Power.setLastUserActivityTimeout(7*24*3600*1000); // one week
|
|
|
|
// assume nothing is on yet
|
|
mUserState = mPowerState = 0;
|
|
|
|
// Add ourself to the Watchdog monitors.
|
|
Watchdog.getInstance().addMonitor(this);
|
|
mScreenOnStartTime = SystemClock.elapsedRealtime();
|
|
}
|
|
|
|
private ContentQueryMap mSettings;
|
|
|
|
void init(Context context, HardwareService hardware, IActivityManager activity,
|
|
BatteryService battery) {
|
|
mHardware = hardware;
|
|
mContext = context;
|
|
mActivityService = activity;
|
|
mBatteryStats = BatteryStatsService.getService();
|
|
mBatteryService = battery;
|
|
|
|
mHandlerThread = new HandlerThread("PowerManagerService") {
|
|
@Override
|
|
protected void onLooperPrepared() {
|
|
super.onLooperPrepared();
|
|
initInThread();
|
|
}
|
|
};
|
|
mHandlerThread.start();
|
|
|
|
synchronized (mHandlerThread) {
|
|
while (!mInitComplete) {
|
|
try {
|
|
mHandlerThread.wait();
|
|
} catch (InterruptedException e) {
|
|
// Ignore
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void initInThread() {
|
|
mHandler = new Handler();
|
|
|
|
mBroadcastWakeLock = new UnsynchronizedWakeLock(
|
|
PowerManager.PARTIAL_WAKE_LOCK, "sleep_broadcast", true);
|
|
mStayOnWhilePluggedInScreenDimLock = new UnsynchronizedWakeLock(
|
|
PowerManager.SCREEN_DIM_WAKE_LOCK, "StayOnWhilePluggedIn Screen Dim", false);
|
|
mStayOnWhilePluggedInPartialLock = new UnsynchronizedWakeLock(
|
|
PowerManager.PARTIAL_WAKE_LOCK, "StayOnWhilePluggedIn Partial", false);
|
|
mPreventScreenOnPartialLock = new UnsynchronizedWakeLock(
|
|
PowerManager.PARTIAL_WAKE_LOCK, "PreventScreenOn Partial", false);
|
|
|
|
mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
|
|
mScreenOnIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
|
|
mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF);
|
|
mScreenOffIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
|
|
|
|
ContentResolver resolver = mContext.getContentResolver();
|
|
Cursor settingsCursor = resolver.query(Settings.System.CONTENT_URI, null,
|
|
"(" + Settings.System.NAME + "=?) or ("
|
|
+ Settings.System.NAME + "=?) or ("
|
|
+ Settings.System.NAME + "=?)",
|
|
new String[]{STAY_ON_WHILE_PLUGGED_IN, SCREEN_OFF_TIMEOUT, DIM_SCREEN},
|
|
null);
|
|
mSettings = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, mHandler);
|
|
SettingsObserver settingsObserver = new SettingsObserver();
|
|
mSettings.addObserver(settingsObserver);
|
|
|
|
// pretend that the settings changed so we will get their initial state
|
|
settingsObserver.update(mSettings, null);
|
|
|
|
// register for the battery changed notifications
|
|
IntentFilter filter = new IntentFilter();
|
|
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
|
|
mContext.registerReceiver(new BatteryReceiver(), filter);
|
|
|
|
// Listen for Gservices changes
|
|
IntentFilter gservicesChangedFilter =
|
|
new IntentFilter(Settings.Gservices.CHANGED_ACTION);
|
|
mContext.registerReceiver(new GservicesChangedReceiver(), gservicesChangedFilter);
|
|
// And explicitly do the initial update of our cached settings
|
|
updateGservicesValues();
|
|
|
|
// turn everything on
|
|
setPowerState(ALL_BRIGHT);
|
|
|
|
synchronized (mHandlerThread) {
|
|
mInitComplete = true;
|
|
mHandlerThread.notifyAll();
|
|
}
|
|
}
|
|
|
|
private class WakeLock implements IBinder.DeathRecipient
|
|
{
|
|
WakeLock(int f, IBinder b, String t, int u) {
|
|
super();
|
|
flags = f;
|
|
binder = b;
|
|
tag = t;
|
|
uid = u == MY_UID ? Process.SYSTEM_UID : u;
|
|
if (u != MY_UID || (
|
|
!"KEEP_SCREEN_ON_FLAG".equals(tag)
|
|
&& !"KeyInputQueue".equals(tag))) {
|
|
monitorType = (f & LOCK_MASK) == PowerManager.PARTIAL_WAKE_LOCK
|
|
? BatteryStats.WAKE_TYPE_PARTIAL
|
|
: BatteryStats.WAKE_TYPE_FULL;
|
|
} else {
|
|
monitorType = -1;
|
|
}
|
|
try {
|
|
b.linkToDeath(this, 0);
|
|
} catch (RemoteException e) {
|
|
binderDied();
|
|
}
|
|
}
|
|
public void binderDied() {
|
|
synchronized (mLocks) {
|
|
releaseWakeLockLocked(this.binder, true);
|
|
}
|
|
}
|
|
final int flags;
|
|
final IBinder binder;
|
|
final String tag;
|
|
final int uid;
|
|
final int monitorType;
|
|
boolean activated = true;
|
|
int minState;
|
|
}
|
|
|
|
private void updateWakeLockLocked() {
|
|
if (mStayOnConditions != 0 && mBatteryService.isPowered(mStayOnConditions)) {
|
|
// keep the device on if we're plugged in and mStayOnWhilePluggedIn is set.
|
|
mStayOnWhilePluggedInScreenDimLock.acquire();
|
|
mStayOnWhilePluggedInPartialLock.acquire();
|
|
} else {
|
|
mStayOnWhilePluggedInScreenDimLock.release();
|
|
mStayOnWhilePluggedInPartialLock.release();
|
|
}
|
|
}
|
|
|
|
private boolean isScreenLock(int flags)
|
|
{
|
|
int n = flags & LOCK_MASK;
|
|
return n == PowerManager.FULL_WAKE_LOCK
|
|
|| n == PowerManager.SCREEN_BRIGHT_WAKE_LOCK
|
|
|| n == PowerManager.SCREEN_DIM_WAKE_LOCK;
|
|
}
|
|
|
|
public void acquireWakeLock(int flags, IBinder lock, String tag) {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
|
|
int uid = Binder.getCallingUid();
|
|
long ident = Binder.clearCallingIdentity();
|
|
try {
|
|
synchronized (mLocks) {
|
|
acquireWakeLockLocked(flags, lock, uid, tag);
|
|
}
|
|
} finally {
|
|
Binder.restoreCallingIdentity(ident);
|
|
}
|
|
}
|
|
|
|
public void acquireWakeLockLocked(int flags, IBinder lock, int uid, String tag) {
|
|
int acquireUid = -1;
|
|
String acquireName = null;
|
|
int acquireType = -1;
|
|
|
|
if (mSpew) {
|
|
Log.d(TAG, "acquireWakeLock flags=0x" + Integer.toHexString(flags) + " tag=" + tag);
|
|
}
|
|
|
|
int index = mLocks.getIndex(lock);
|
|
WakeLock wl;
|
|
boolean newlock;
|
|
if (index < 0) {
|
|
wl = new WakeLock(flags, lock, tag, uid);
|
|
switch (wl.flags & LOCK_MASK)
|
|
{
|
|
case PowerManager.FULL_WAKE_LOCK:
|
|
wl.minState = (mKeyboardVisible ? ALL_BRIGHT : SCREEN_BUTTON_BRIGHT);
|
|
break;
|
|
case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
|
|
wl.minState = SCREEN_BRIGHT;
|
|
break;
|
|
case PowerManager.SCREEN_DIM_WAKE_LOCK:
|
|
wl.minState = SCREEN_DIM;
|
|
break;
|
|
case PowerManager.PARTIAL_WAKE_LOCK:
|
|
break;
|
|
default:
|
|
// just log and bail. we're in the server, so don't
|
|
// throw an exception.
|
|
Log.e(TAG, "bad wakelock type for lock '" + tag + "' "
|
|
+ " flags=" + flags);
|
|
return;
|
|
}
|
|
mLocks.addLock(wl);
|
|
newlock = true;
|
|
} else {
|
|
wl = mLocks.get(index);
|
|
newlock = false;
|
|
}
|
|
if (isScreenLock(flags)) {
|
|
// if this causes a wakeup, we reactivate all of the locks and
|
|
// set it to whatever they want. otherwise, we modulate that
|
|
// by the current state so we never turn it more on than
|
|
// it already is.
|
|
if ((wl.flags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0) {
|
|
reactivateWakeLocksLocked();
|
|
if (mSpew) {
|
|
Log.d(TAG, "wakeup here mUserState=0x" + Integer.toHexString(mUserState)
|
|
+ " mLocks.gatherState()=0x"
|
|
+ Integer.toHexString(mLocks.gatherState())
|
|
+ " mWakeLockState=0x" + Integer.toHexString(mWakeLockState));
|
|
}
|
|
mWakeLockState = mLocks.gatherState();
|
|
} else {
|
|
if (mSpew) {
|
|
Log.d(TAG, "here mUserState=0x" + Integer.toHexString(mUserState)
|
|
+ " mLocks.gatherState()=0x"
|
|
+ Integer.toHexString(mLocks.gatherState())
|
|
+ " mWakeLockState=0x" + Integer.toHexString(mWakeLockState));
|
|
}
|
|
mWakeLockState = (mUserState | mWakeLockState) & mLocks.gatherState();
|
|
}
|
|
setPowerState(mWakeLockState | mUserState);
|
|
}
|
|
else if ((flags & LOCK_MASK) == PowerManager.PARTIAL_WAKE_LOCK) {
|
|
if (newlock) {
|
|
mPartialCount++;
|
|
if (mPartialCount == 1) {
|
|
if (LOG_PARTIAL_WL) EventLog.writeEvent(LOG_POWER_PARTIAL_WAKE_STATE, 1, tag);
|
|
}
|
|
}
|
|
Power.acquireWakeLock(Power.PARTIAL_WAKE_LOCK,PARTIAL_NAME);
|
|
}
|
|
if (newlock) {
|
|
acquireUid = wl.uid;
|
|
acquireName = wl.tag;
|
|
acquireType = wl.monitorType;
|
|
}
|
|
|
|
if (acquireType >= 0) {
|
|
try {
|
|
mBatteryStats.noteStartWakelock(acquireUid, acquireName, acquireType);
|
|
} catch (RemoteException e) {
|
|
// Ignore
|
|
}
|
|
}
|
|
}
|
|
|
|
public void releaseWakeLock(IBinder lock) {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
|
|
|
|
synchronized (mLocks) {
|
|
releaseWakeLockLocked(lock, false);
|
|
}
|
|
}
|
|
|
|
private void releaseWakeLockLocked(IBinder lock, boolean death) {
|
|
int releaseUid;
|
|
String releaseName;
|
|
int releaseType;
|
|
|
|
WakeLock wl = mLocks.removeLock(lock);
|
|
if (wl == null) {
|
|
return;
|
|
}
|
|
|
|
if (mSpew) {
|
|
Log.d(TAG, "releaseWakeLock flags=0x"
|
|
+ Integer.toHexString(wl.flags) + " tag=" + wl.tag);
|
|
}
|
|
|
|
if (isScreenLock(wl.flags)) {
|
|
mWakeLockState = mLocks.gatherState();
|
|
// goes in the middle to reduce flicker
|
|
if ((wl.flags & PowerManager.ON_AFTER_RELEASE) != 0) {
|
|
userActivity(SystemClock.uptimeMillis(), false);
|
|
}
|
|
setPowerState(mWakeLockState | mUserState);
|
|
}
|
|
else if ((wl.flags & LOCK_MASK) == PowerManager.PARTIAL_WAKE_LOCK) {
|
|
mPartialCount--;
|
|
if (mPartialCount == 0) {
|
|
if (LOG_PARTIAL_WL) EventLog.writeEvent(LOG_POWER_PARTIAL_WAKE_STATE, 0, wl.tag);
|
|
Power.releaseWakeLock(PARTIAL_NAME);
|
|
}
|
|
}
|
|
// Unlink the lock from the binder.
|
|
wl.binder.unlinkToDeath(wl, 0);
|
|
releaseUid = wl.uid;
|
|
releaseName = wl.tag;
|
|
releaseType = wl.monitorType;
|
|
|
|
if (releaseType >= 0) {
|
|
long origId = Binder.clearCallingIdentity();
|
|
try {
|
|
mBatteryStats.noteStopWakelock(releaseUid, releaseName, releaseType);
|
|
} catch (RemoteException e) {
|
|
// Ignore
|
|
} finally {
|
|
Binder.restoreCallingIdentity(origId);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void reactivateWakeLocksLocked()
|
|
{
|
|
int N = mLocks.size();
|
|
for (int i=0; i<N; i++) {
|
|
WakeLock wl = mLocks.get(i);
|
|
if (isScreenLock(wl.flags)) {
|
|
mLocks.get(i).activated = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
private class PokeLock implements IBinder.DeathRecipient
|
|
{
|
|
PokeLock(int p, IBinder b, String t) {
|
|
super();
|
|
this.pokey = p;
|
|
this.binder = b;
|
|
this.tag = t;
|
|
try {
|
|
b.linkToDeath(this, 0);
|
|
} catch (RemoteException e) {
|
|
binderDied();
|
|
}
|
|
}
|
|
public void binderDied() {
|
|
setPokeLock(0, this.binder, this.tag);
|
|
}
|
|
int pokey;
|
|
IBinder binder;
|
|
String tag;
|
|
boolean awakeOnSet;
|
|
}
|
|
|
|
public void setPokeLock(int pokey, IBinder token, String tag) {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
|
|
if (token == null) {
|
|
Log.e(TAG, "setPokeLock got null token for tag='" + tag + "'");
|
|
return;
|
|
}
|
|
|
|
if ((pokey & POKE_LOCK_TIMEOUT_MASK) == POKE_LOCK_TIMEOUT_MASK) {
|
|
throw new IllegalArgumentException("setPokeLock can't have both POKE_LOCK_SHORT_TIMEOUT"
|
|
+ " and POKE_LOCK_MEDIUM_TIMEOUT");
|
|
}
|
|
|
|
synchronized (mLocks) {
|
|
if (pokey != 0) {
|
|
PokeLock p = mPokeLocks.get(token);
|
|
int oldPokey = 0;
|
|
if (p != null) {
|
|
oldPokey = p.pokey;
|
|
p.pokey = pokey;
|
|
} else {
|
|
p = new PokeLock(pokey, token, tag);
|
|
mPokeLocks.put(token, p);
|
|
}
|
|
int oldTimeout = oldPokey & POKE_LOCK_TIMEOUT_MASK;
|
|
int newTimeout = pokey & POKE_LOCK_TIMEOUT_MASK;
|
|
if (((mPowerState & SCREEN_ON_BIT) == 0) && (oldTimeout != newTimeout)) {
|
|
p.awakeOnSet = true;
|
|
}
|
|
} else {
|
|
mPokeLocks.remove(token);
|
|
}
|
|
|
|
int oldPokey = mPokey;
|
|
int cumulative = 0;
|
|
boolean oldAwakeOnSet = mPokeAwakeOnSet;
|
|
boolean awakeOnSet = false;
|
|
for (PokeLock p: mPokeLocks.values()) {
|
|
cumulative |= p.pokey;
|
|
if (p.awakeOnSet) {
|
|
awakeOnSet = true;
|
|
}
|
|
}
|
|
mPokey = cumulative;
|
|
mPokeAwakeOnSet = awakeOnSet;
|
|
|
|
int oldCumulativeTimeout = oldPokey & POKE_LOCK_TIMEOUT_MASK;
|
|
int newCumulativeTimeout = pokey & POKE_LOCK_TIMEOUT_MASK;
|
|
|
|
if (oldCumulativeTimeout != newCumulativeTimeout) {
|
|
setScreenOffTimeoutsLocked();
|
|
// reset the countdown timer, but use the existing nextState so it doesn't
|
|
// change anything
|
|
setTimeoutLocked(SystemClock.uptimeMillis(), mTimeoutTask.nextState);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static String lockType(int type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case PowerManager.FULL_WAKE_LOCK:
|
|
return "FULL_WAKE_LOCK ";
|
|
case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
|
|
return "SCREEN_BRIGHT_WAKE_LOCK";
|
|
case PowerManager.SCREEN_DIM_WAKE_LOCK:
|
|
return "SCREEN_DIM_WAKE_LOCK ";
|
|
case PowerManager.PARTIAL_WAKE_LOCK:
|
|
return "PARTIAL_WAKE_LOCK ";
|
|
default:
|
|
return "??? ";
|
|
}
|
|
}
|
|
|
|
private static String dumpPowerState(int state) {
|
|
return (((state & KEYBOARD_BRIGHT_BIT) != 0)
|
|
? "KEYBOARD_BRIGHT_BIT " : "")
|
|
+ (((state & SCREEN_BRIGHT_BIT) != 0)
|
|
? "SCREEN_BRIGHT_BIT " : "")
|
|
+ (((state & SCREEN_ON_BIT) != 0)
|
|
? "SCREEN_ON_BIT " : "")
|
|
+ (((state & BATTERY_LOW_BIT) != 0)
|
|
? "BATTERY_LOW_BIT " : "");
|
|
}
|
|
|
|
@Override
|
|
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
|
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
|
|
!= PackageManager.PERMISSION_GRANTED) {
|
|
pw.println("Permission Denial: can't dump PowerManager from from pid="
|
|
+ Binder.getCallingPid()
|
|
+ ", uid=" + Binder.getCallingUid());
|
|
return;
|
|
}
|
|
|
|
long now = SystemClock.uptimeMillis();
|
|
|
|
pw.println("Power Manager State:");
|
|
pw.println(" mIsPowered=" + mIsPowered
|
|
+ " mPowerState=" + mPowerState
|
|
+ " mScreenOffTime=" + (SystemClock.elapsedRealtime()-mScreenOffTime)
|
|
+ " ms");
|
|
pw.println(" mPartialCount=" + mPartialCount);
|
|
pw.println(" mWakeLockState=" + dumpPowerState(mWakeLockState));
|
|
pw.println(" mUserState=" + dumpPowerState(mUserState));
|
|
pw.println(" mPowerState=" + dumpPowerState(mPowerState));
|
|
pw.println(" mLocks.gather=" + dumpPowerState(mLocks.gatherState()));
|
|
pw.println(" mNextTimeout=" + mNextTimeout + " now=" + now
|
|
+ " " + ((mNextTimeout-now)/1000) + "s from now");
|
|
pw.println(" mDimScreen=" + mDimScreen
|
|
+ " mStayOnConditions=" + mStayOnConditions);
|
|
pw.println(" mOffBecauseOfUser=" + mOffBecauseOfUser
|
|
+ " mUserState=" + mUserState);
|
|
pw.println(" mBroadcastQueue={" + mBroadcastQueue[0] + ',' + mBroadcastQueue[1]
|
|
+ ',' + mBroadcastQueue[2] + "}");
|
|
pw.println(" mBroadcastWhy={" + mBroadcastWhy[0] + ',' + mBroadcastWhy[1]
|
|
+ ',' + mBroadcastWhy[2] + "}");
|
|
pw.println(" mPokey=" + mPokey + " mPokeAwakeonSet=" + mPokeAwakeOnSet);
|
|
pw.println(" mKeyboardVisible=" + mKeyboardVisible
|
|
+ " mUserActivityAllowed=" + mUserActivityAllowed);
|
|
pw.println(" mKeylightDelay=" + mKeylightDelay + " mDimDelay=" + mDimDelay
|
|
+ " mScreenOffDelay=" + mScreenOffDelay);
|
|
pw.println(" mPreventScreenOn=" + mPreventScreenOn
|
|
+ " mScreenBrightnessOverride=" + mScreenBrightnessOverride);
|
|
pw.println(" mTotalDelaySetting=" + mTotalDelaySetting);
|
|
pw.println(" mBroadcastWakeLock=" + mBroadcastWakeLock);
|
|
pw.println(" mStayOnWhilePluggedInScreenDimLock=" + mStayOnWhilePluggedInScreenDimLock);
|
|
pw.println(" mStayOnWhilePluggedInPartialLock=" + mStayOnWhilePluggedInPartialLock);
|
|
pw.println(" mPreventScreenOnPartialLock=" + mPreventScreenOnPartialLock);
|
|
mScreenBrightness.dump(pw, " mScreenBrightness: ");
|
|
mKeyboardBrightness.dump(pw, " mKeyboardBrightness: ");
|
|
mButtonBrightness.dump(pw, " mButtonBrightness: ");
|
|
|
|
int N = mLocks.size();
|
|
pw.println();
|
|
pw.println("mLocks.size=" + N + ":");
|
|
for (int i=0; i<N; i++) {
|
|
WakeLock wl = mLocks.get(i);
|
|
String type = lockType(wl.flags & LOCK_MASK);
|
|
String acquireCausesWakeup = "";
|
|
if ((wl.flags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0) {
|
|
acquireCausesWakeup = "ACQUIRE_CAUSES_WAKEUP ";
|
|
}
|
|
String activated = "";
|
|
if (wl.activated) {
|
|
activated = " activated";
|
|
}
|
|
pw.println(" " + type + " '" + wl.tag + "'" + acquireCausesWakeup
|
|
+ activated + " (minState=" + wl.minState + ")");
|
|
}
|
|
|
|
pw.println();
|
|
pw.println("mPokeLocks.size=" + mPokeLocks.size() + ":");
|
|
for (PokeLock p: mPokeLocks.values()) {
|
|
pw.println(" poke lock '" + p.tag + "':"
|
|
+ ((p.pokey & POKE_LOCK_IGNORE_CHEEK_EVENTS) != 0
|
|
? " POKE_LOCK_IGNORE_CHEEK_EVENTS" : "")
|
|
+ ((p.pokey & POKE_LOCK_IGNORE_TOUCH_AND_CHEEK_EVENTS) != 0
|
|
? " POKE_LOCK_IGNORE_TOUCH_AND_CHEEK_EVENTS" : "")
|
|
+ ((p.pokey & POKE_LOCK_SHORT_TIMEOUT) != 0
|
|
? " POKE_LOCK_SHORT_TIMEOUT" : "")
|
|
+ ((p.pokey & POKE_LOCK_MEDIUM_TIMEOUT) != 0
|
|
? " POKE_LOCK_MEDIUM_TIMEOUT" : ""));
|
|
}
|
|
|
|
pw.println();
|
|
}
|
|
|
|
private void setTimeoutLocked(long now, int nextState)
|
|
{
|
|
if (mDoneBooting) {
|
|
mHandler.removeCallbacks(mTimeoutTask);
|
|
mTimeoutTask.nextState = nextState;
|
|
long when = now;
|
|
switch (nextState)
|
|
{
|
|
case SCREEN_BRIGHT:
|
|
when += mKeylightDelay;
|
|
break;
|
|
case SCREEN_DIM:
|
|
if (mDimDelay >= 0) {
|
|
when += mDimDelay;
|
|
break;
|
|
} else {
|
|
Log.w(TAG, "mDimDelay=" + mDimDelay + " while trying to dim");
|
|
}
|
|
case SCREEN_OFF:
|
|
synchronized (mLocks) {
|
|
when += mScreenOffDelay;
|
|
}
|
|
break;
|
|
}
|
|
if (mSpew) {
|
|
Log.d(TAG, "setTimeoutLocked now=" + now + " nextState=" + nextState
|
|
+ " when=" + when);
|
|
}
|
|
mHandler.postAtTime(mTimeoutTask, when);
|
|
mNextTimeout = when; // for debugging
|
|
}
|
|
}
|
|
|
|
private void cancelTimerLocked()
|
|
{
|
|
mHandler.removeCallbacks(mTimeoutTask);
|
|
mTimeoutTask.nextState = -1;
|
|
}
|
|
|
|
private class TimeoutTask implements Runnable
|
|
{
|
|
int nextState; // access should be synchronized on mLocks
|
|
public void run()
|
|
{
|
|
synchronized (mLocks) {
|
|
if (mSpew) {
|
|
Log.d(TAG, "user activity timeout timed out nextState=" + this.nextState);
|
|
}
|
|
|
|
if (nextState == -1) {
|
|
return;
|
|
}
|
|
|
|
mUserState = this.nextState;
|
|
setPowerState(this.nextState | mWakeLockState);
|
|
|
|
long now = SystemClock.uptimeMillis();
|
|
|
|
switch (this.nextState)
|
|
{
|
|
case SCREEN_BRIGHT:
|
|
if (mDimDelay >= 0) {
|
|
setTimeoutLocked(now, SCREEN_DIM);
|
|
break;
|
|
}
|
|
case SCREEN_DIM:
|
|
setTimeoutLocked(now, SCREEN_OFF);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void sendNotificationLocked(boolean on, int why)
|
|
{
|
|
if (!on) {
|
|
mStillNeedSleepNotification = false;
|
|
}
|
|
|
|
// Add to the queue.
|
|
int index = 0;
|
|
while (mBroadcastQueue[index] != -1) {
|
|
index++;
|
|
}
|
|
mBroadcastQueue[index] = on ? 1 : 0;
|
|
mBroadcastWhy[index] = why;
|
|
|
|
// If we added it position 2, then there is a pair that can be stripped.
|
|
// If we added it position 1 and we're turning the screen off, we can strip
|
|
// the pair and do nothing, because the screen is already off, and therefore
|
|
// keyguard has already been enabled.
|
|
// However, if we added it at position 1 and we're turning it on, then position
|
|
// 0 was to turn it off, and we can't strip that, because keyguard needs to come
|
|
// on, so have to run the queue then.
|
|
if (index == 2) {
|
|
// Also, while we're collapsing them, if it's going to be an "off," and one
|
|
// is off because of user, then use that, regardless of whether it's the first
|
|
// or second one.
|
|
if (!on && why == WindowManagerPolicy.OFF_BECAUSE_OF_USER) {
|
|
mBroadcastWhy[0] = WindowManagerPolicy.OFF_BECAUSE_OF_USER;
|
|
}
|
|
mBroadcastQueue[0] = on ? 1 : 0;
|
|
mBroadcastQueue[1] = -1;
|
|
mBroadcastQueue[2] = -1;
|
|
index = 0;
|
|
}
|
|
if (index == 1 && !on) {
|
|
mBroadcastQueue[0] = -1;
|
|
mBroadcastQueue[1] = -1;
|
|
index = -1;
|
|
// The wake lock was being held, but we're not actually going to do any
|
|
// broadcasts, so release the wake lock.
|
|
EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_STOP, 1, mBroadcastWakeLock.mCount);
|
|
mBroadcastWakeLock.release();
|
|
}
|
|
|
|
// Now send the message.
|
|
if (index >= 0) {
|
|
// Acquire the broadcast wake lock before changing the power
|
|
// state. It will be release after the broadcast is sent.
|
|
// We always increment the ref count for each notification in the queue
|
|
// and always decrement when that notification is handled.
|
|
mBroadcastWakeLock.acquire();
|
|
EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_SEND, mBroadcastWakeLock.mCount);
|
|
mHandler.post(mNotificationTask);
|
|
}
|
|
}
|
|
|
|
private Runnable mNotificationTask = new Runnable()
|
|
{
|
|
public void run()
|
|
{
|
|
while (true) {
|
|
int value;
|
|
int why;
|
|
WindowManagerPolicy policy;
|
|
synchronized (mLocks) {
|
|
value = mBroadcastQueue[0];
|
|
why = mBroadcastWhy[0];
|
|
for (int i=0; i<2; i++) {
|
|
mBroadcastQueue[i] = mBroadcastQueue[i+1];
|
|
mBroadcastWhy[i] = mBroadcastWhy[i+1];
|
|
}
|
|
policy = getPolicyLocked();
|
|
}
|
|
if (value == 1) {
|
|
mScreenOnStart = SystemClock.uptimeMillis();
|
|
|
|
policy.screenTurnedOn();
|
|
try {
|
|
ActivityManagerNative.getDefault().wakingUp();
|
|
} catch (RemoteException e) {
|
|
// ignore it
|
|
}
|
|
|
|
if (mSpew) {
|
|
Log.d(TAG, "mBroadcastWakeLock=" + mBroadcastWakeLock);
|
|
}
|
|
if (mContext != null && ActivityManagerNative.isSystemReady()) {
|
|
mContext.sendOrderedBroadcast(mScreenOnIntent, null,
|
|
mScreenOnBroadcastDone, mHandler, 0, null, null);
|
|
} else {
|
|
synchronized (mLocks) {
|
|
EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_STOP, 2,
|
|
mBroadcastWakeLock.mCount);
|
|
mBroadcastWakeLock.release();
|
|
}
|
|
}
|
|
}
|
|
else if (value == 0) {
|
|
mScreenOffStart = SystemClock.uptimeMillis();
|
|
|
|
policy.screenTurnedOff(why);
|
|
try {
|
|
ActivityManagerNative.getDefault().goingToSleep();
|
|
} catch (RemoteException e) {
|
|
// ignore it.
|
|
}
|
|
|
|
if (mContext != null && ActivityManagerNative.isSystemReady()) {
|
|
mContext.sendOrderedBroadcast(mScreenOffIntent, null,
|
|
mScreenOffBroadcastDone, mHandler, 0, null, null);
|
|
} else {
|
|
synchronized (mLocks) {
|
|
EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_STOP, 3,
|
|
mBroadcastWakeLock.mCount);
|
|
mBroadcastWakeLock.release();
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// If we're in this case, then this handler is running for a previous
|
|
// paired transaction. mBroadcastWakeLock will already have been released.
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
long mScreenOnStart;
|
|
private BroadcastReceiver mScreenOnBroadcastDone = new BroadcastReceiver() {
|
|
public void onReceive(Context context, Intent intent) {
|
|
synchronized (mLocks) {
|
|
EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_DONE, 1,
|
|
SystemClock.uptimeMillis() - mScreenOnStart, mBroadcastWakeLock.mCount);
|
|
mBroadcastWakeLock.release();
|
|
}
|
|
}
|
|
};
|
|
|
|
long mScreenOffStart;
|
|
private BroadcastReceiver mScreenOffBroadcastDone = new BroadcastReceiver() {
|
|
public void onReceive(Context context, Intent intent) {
|
|
synchronized (mLocks) {
|
|
EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_DONE, 0,
|
|
SystemClock.uptimeMillis() - mScreenOffStart, mBroadcastWakeLock.mCount);
|
|
mBroadcastWakeLock.release();
|
|
}
|
|
}
|
|
};
|
|
|
|
void logPointerUpEvent() {
|
|
if (LOG_TOUCH_DOWNS) {
|
|
mTotalTouchDownTime += SystemClock.elapsedRealtime() - mLastTouchDown;
|
|
mLastTouchDown = 0;
|
|
}
|
|
}
|
|
|
|
void logPointerDownEvent() {
|
|
if (LOG_TOUCH_DOWNS) {
|
|
// If we are not already timing a down/up sequence
|
|
if (mLastTouchDown == 0) {
|
|
mLastTouchDown = SystemClock.elapsedRealtime();
|
|
mTouchCycles++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Prevents the screen from turning on even if it *should* turn on due
|
|
* to a subsequent full wake lock being acquired.
|
|
* <p>
|
|
* This is a temporary hack that allows an activity to "cover up" any
|
|
* display glitches that happen during the activity's startup
|
|
* sequence. (Specifically, this API was added to work around a
|
|
* cosmetic bug in the "incoming call" sequence, where the lock screen
|
|
* would flicker briefly before the incoming call UI became visible.)
|
|
* TODO: There ought to be a more elegant way of doing this,
|
|
* probably by having the PowerManager and ActivityManager
|
|
* work together to let apps specify that the screen on/off
|
|
* state should be synchronized with the Activity lifecycle.
|
|
* <p>
|
|
* Note that calling preventScreenOn(true) will NOT turn the screen
|
|
* off if it's currently on. (This API only affects *future*
|
|
* acquisitions of full wake locks.)
|
|
* But calling preventScreenOn(false) WILL turn the screen on if
|
|
* it's currently off because of a prior preventScreenOn(true) call.
|
|
* <p>
|
|
* Any call to preventScreenOn(true) MUST be followed promptly by a call
|
|
* to preventScreenOn(false). In fact, if the preventScreenOn(false)
|
|
* call doesn't occur within 5 seconds, we'll turn the screen back on
|
|
* ourselves (and log a warning about it); this prevents a buggy app
|
|
* from disabling the screen forever.)
|
|
* <p>
|
|
* TODO: this feature should really be controlled by a new type of poke
|
|
* lock (rather than an IPowerManager call).
|
|
*/
|
|
public void preventScreenOn(boolean prevent) {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
|
|
|
|
synchronized (mLocks) {
|
|
if (prevent) {
|
|
// First of all, grab a partial wake lock to
|
|
// make sure the CPU stays on during the entire
|
|
// preventScreenOn(true) -> preventScreenOn(false) sequence.
|
|
mPreventScreenOnPartialLock.acquire();
|
|
|
|
// Post a forceReenableScreen() call (for 5 seconds in the
|
|
// future) to make sure the matching preventScreenOn(false) call
|
|
// has happened by then.
|
|
mHandler.removeCallbacks(mForceReenableScreenTask);
|
|
mHandler.postDelayed(mForceReenableScreenTask, 5000);
|
|
|
|
// Finally, set the flag that prevents the screen from turning on.
|
|
// (Below, in setPowerState(), we'll check mPreventScreenOn and
|
|
// we *won't* call Power.setScreenState(true) if it's set.)
|
|
mPreventScreenOn = true;
|
|
} else {
|
|
// (Re)enable the screen.
|
|
mPreventScreenOn = false;
|
|
|
|
// We're "undoing" a the prior preventScreenOn(true) call, so we
|
|
// no longer need the 5-second safeguard.
|
|
mHandler.removeCallbacks(mForceReenableScreenTask);
|
|
|
|
// Forcibly turn on the screen if it's supposed to be on. (This
|
|
// handles the case where the screen is currently off because of
|
|
// a prior preventScreenOn(true) call.)
|
|
if ((mPowerState & SCREEN_ON_BIT) != 0) {
|
|
if (mSpew) {
|
|
Log.d(TAG,
|
|
"preventScreenOn: turning on after a prior preventScreenOn(true)!");
|
|
}
|
|
int err = Power.setScreenState(true);
|
|
if (err != 0) {
|
|
Log.w(TAG, "preventScreenOn: error from Power.setScreenState(): " + err);
|
|
}
|
|
}
|
|
|
|
// Release the partial wake lock that we held during the
|
|
// preventScreenOn(true) -> preventScreenOn(false) sequence.
|
|
mPreventScreenOnPartialLock.release();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void setScreenBrightnessOverride(int brightness) {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
|
|
|
|
synchronized (mLocks) {
|
|
if (mScreenBrightnessOverride != brightness) {
|
|
mScreenBrightnessOverride = brightness;
|
|
updateLightsLocked(mPowerState, SCREEN_ON_BIT);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sanity-check that gets called 5 seconds after any call to
|
|
* preventScreenOn(true). This ensures that the original call
|
|
* is followed promptly by a call to preventScreenOn(false).
|
|
*/
|
|
private void forceReenableScreen() {
|
|
// We shouldn't get here at all if mPreventScreenOn is false, since
|
|
// we should have already removed any existing
|
|
// mForceReenableScreenTask messages...
|
|
if (!mPreventScreenOn) {
|
|
Log.w(TAG, "forceReenableScreen: mPreventScreenOn is false, nothing to do");
|
|
return;
|
|
}
|
|
|
|
// Uh oh. It's been 5 seconds since a call to
|
|
// preventScreenOn(true) and we haven't re-enabled the screen yet.
|
|
// This means the app that called preventScreenOn(true) is either
|
|
// slow (i.e. it took more than 5 seconds to call preventScreenOn(false)),
|
|
// or buggy (i.e. it forgot to call preventScreenOn(false), or
|
|
// crashed before doing so.)
|
|
|
|
// Log a warning, and forcibly turn the screen back on.
|
|
Log.w(TAG, "App called preventScreenOn(true) but didn't promptly reenable the screen! "
|
|
+ "Forcing the screen back on...");
|
|
preventScreenOn(false);
|
|
}
|
|
|
|
private Runnable mForceReenableScreenTask = new Runnable() {
|
|
public void run() {
|
|
forceReenableScreen();
|
|
}
|
|
};
|
|
|
|
private void setPowerState(int state)
|
|
{
|
|
setPowerState(state, false, false);
|
|
}
|
|
|
|
private void setPowerState(int newState, boolean noChangeLights, boolean becauseOfUser)
|
|
{
|
|
synchronized (mLocks) {
|
|
int err;
|
|
|
|
if (mSpew) {
|
|
Log.d(TAG, "setPowerState: mPowerState=0x" + Integer.toHexString(mPowerState)
|
|
+ " newState=0x" + Integer.toHexString(newState)
|
|
+ " noChangeLights=" + noChangeLights);
|
|
}
|
|
|
|
if (noChangeLights) {
|
|
newState = (newState & ~LIGHTS_MASK) | (mPowerState & LIGHTS_MASK);
|
|
}
|
|
|
|
if (batteryIsLow()) {
|
|
newState |= BATTERY_LOW_BIT;
|
|
} else {
|
|
newState &= ~BATTERY_LOW_BIT;
|
|
}
|
|
if (newState == mPowerState) {
|
|
return;
|
|
}
|
|
|
|
if (!mDoneBooting) {
|
|
newState |= ALL_BRIGHT;
|
|
}
|
|
|
|
boolean oldScreenOn = (mPowerState & SCREEN_ON_BIT) != 0;
|
|
boolean newScreenOn = (newState & SCREEN_ON_BIT) != 0;
|
|
|
|
if (mSpew) {
|
|
Log.d(TAG, "setPowerState: mPowerState=" + mPowerState
|
|
+ " newState=" + newState + " noChangeLights=" + noChangeLights);
|
|
Log.d(TAG, " oldKeyboardBright=" + ((mPowerState & KEYBOARD_BRIGHT_BIT) != 0)
|
|
+ " newKeyboardBright=" + ((newState & KEYBOARD_BRIGHT_BIT) != 0));
|
|
Log.d(TAG, " oldScreenBright=" + ((mPowerState & SCREEN_BRIGHT_BIT) != 0)
|
|
+ " newScreenBright=" + ((newState & SCREEN_BRIGHT_BIT) != 0));
|
|
Log.d(TAG, " oldButtonBright=" + ((mPowerState & BUTTON_BRIGHT_BIT) != 0)
|
|
+ " newButtonBright=" + ((newState & BUTTON_BRIGHT_BIT) != 0));
|
|
Log.d(TAG, " oldScreenOn=" + oldScreenOn
|
|
+ " newScreenOn=" + newScreenOn);
|
|
Log.d(TAG, " oldBatteryLow=" + ((mPowerState & BATTERY_LOW_BIT) != 0)
|
|
+ " newBatteryLow=" + ((newState & BATTERY_LOW_BIT) != 0));
|
|
}
|
|
|
|
if (mPowerState != newState) {
|
|
updateLightsLocked(newState, 0);
|
|
mPowerState = (mPowerState & ~LIGHTS_MASK) | (newState & LIGHTS_MASK);
|
|
}
|
|
|
|
if (oldScreenOn != newScreenOn) {
|
|
if (newScreenOn) {
|
|
// When the user presses the power button, we need to always send out the
|
|
// notification that it's going to sleep so the keyguard goes on. But
|
|
// we can't do that until the screen fades out, so we don't show the keyguard
|
|
// too early.
|
|
if (mStillNeedSleepNotification) {
|
|
sendNotificationLocked(false, WindowManagerPolicy.OFF_BECAUSE_OF_USER);
|
|
}
|
|
|
|
// Turn on the screen UNLESS there was a prior
|
|
// preventScreenOn(true) request. (Note that the lifetime
|
|
// of a single preventScreenOn() request is limited to 5
|
|
// seconds to prevent a buggy app from disabling the
|
|
// screen forever; see forceReenableScreen().)
|
|
boolean reallyTurnScreenOn = true;
|
|
if (mSpew) {
|
|
Log.d(TAG, "- turning screen on... mPreventScreenOn = "
|
|
+ mPreventScreenOn);
|
|
}
|
|
|
|
if (mPreventScreenOn) {
|
|
if (mSpew) {
|
|
Log.d(TAG, "- PREVENTING screen from really turning on!");
|
|
}
|
|
reallyTurnScreenOn = false;
|
|
}
|
|
if (reallyTurnScreenOn) {
|
|
err = Power.setScreenState(true);
|
|
long identity = Binder.clearCallingIdentity();
|
|
try {
|
|
mBatteryStats.noteScreenBrightness(
|
|
getPreferredBrightness());
|
|
mBatteryStats.noteScreenOn();
|
|
} catch (RemoteException e) {
|
|
Log.w(TAG, "RemoteException calling noteScreenOn on BatteryStatsService", e);
|
|
} finally {
|
|
Binder.restoreCallingIdentity(identity);
|
|
}
|
|
} else {
|
|
Power.setScreenState(false);
|
|
// But continue as if we really did turn the screen on...
|
|
err = 0;
|
|
}
|
|
|
|
mScreenOnStartTime = SystemClock.elapsedRealtime();
|
|
mLastTouchDown = 0;
|
|
mTotalTouchDownTime = 0;
|
|
mTouchCycles = 0;
|
|
EventLog.writeEvent(LOG_POWER_SCREEN_STATE, 1, becauseOfUser ? 1 : 0,
|
|
mTotalTouchDownTime, mTouchCycles);
|
|
if (err == 0) {
|
|
mPowerState |= SCREEN_ON_BIT;
|
|
sendNotificationLocked(true, -1);
|
|
}
|
|
} else {
|
|
mScreenOffTime = SystemClock.elapsedRealtime();
|
|
long identity = Binder.clearCallingIdentity();
|
|
try {
|
|
mBatteryStats.noteScreenOff();
|
|
} catch (RemoteException e) {
|
|
Log.w(TAG, "RemoteException calling noteScreenOff on BatteryStatsService", e);
|
|
} finally {
|
|
Binder.restoreCallingIdentity(identity);
|
|
}
|
|
mPowerState &= ~SCREEN_ON_BIT;
|
|
if (!mScreenBrightness.animating) {
|
|
err = screenOffFinishedAnimatingLocked(becauseOfUser);
|
|
} else {
|
|
mOffBecauseOfUser = becauseOfUser;
|
|
err = 0;
|
|
mLastTouchDown = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private int screenOffFinishedAnimatingLocked(boolean becauseOfUser) {
|
|
// I don't think we need to check the current state here because all of these
|
|
// Power.setScreenState and sendNotificationLocked can both handle being
|
|
// called multiple times in the same state. -joeo
|
|
EventLog.writeEvent(LOG_POWER_SCREEN_STATE, 0, becauseOfUser ? 1 : 0,
|
|
mTotalTouchDownTime, mTouchCycles);
|
|
mLastTouchDown = 0;
|
|
int err = Power.setScreenState(false);
|
|
if (mScreenOnStartTime != 0) {
|
|
mScreenOnTime += SystemClock.elapsedRealtime() - mScreenOnStartTime;
|
|
mScreenOnStartTime = 0;
|
|
}
|
|
if (err == 0) {
|
|
int why = becauseOfUser
|
|
? WindowManagerPolicy.OFF_BECAUSE_OF_USER
|
|
: WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT;
|
|
sendNotificationLocked(false, why);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
private boolean batteryIsLow() {
|
|
return (!mIsPowered &&
|
|
mBatteryService.getBatteryLevel() <= Power.LOW_BATTERY_THRESHOLD);
|
|
}
|
|
|
|
private void updateLightsLocked(int newState, int forceState) {
|
|
final int oldState = mPowerState;
|
|
final int realDifference = (newState ^ oldState);
|
|
final int difference = realDifference | forceState;
|
|
if (difference == 0) {
|
|
return;
|
|
}
|
|
|
|
int offMask = 0;
|
|
int dimMask = 0;
|
|
int onMask = 0;
|
|
|
|
int preferredBrightness = getPreferredBrightness();
|
|
boolean startAnimation = false;
|
|
|
|
if ((difference & KEYBOARD_BRIGHT_BIT) != 0) {
|
|
if (ANIMATE_KEYBOARD_LIGHTS) {
|
|
if ((newState & KEYBOARD_BRIGHT_BIT) == 0) {
|
|
mKeyboardBrightness.setTargetLocked(Power.BRIGHTNESS_OFF,
|
|
ANIM_STEPS, INITIAL_KEYBOARD_BRIGHTNESS,
|
|
preferredBrightness);
|
|
} else {
|
|
mKeyboardBrightness.setTargetLocked(preferredBrightness,
|
|
ANIM_STEPS, INITIAL_KEYBOARD_BRIGHTNESS,
|
|
Power.BRIGHTNESS_OFF);
|
|
}
|
|
startAnimation = true;
|
|
} else {
|
|
if ((newState & KEYBOARD_BRIGHT_BIT) == 0) {
|
|
offMask |= KEYBOARD_BRIGHT_BIT;
|
|
} else {
|
|
onMask |= KEYBOARD_BRIGHT_BIT;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((difference & BUTTON_BRIGHT_BIT) != 0) {
|
|
if (ANIMATE_BUTTON_LIGHTS) {
|
|
if ((newState & BUTTON_BRIGHT_BIT) == 0) {
|
|
mButtonBrightness.setTargetLocked(Power.BRIGHTNESS_OFF,
|
|
ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
|
|
preferredBrightness);
|
|
} else {
|
|
mButtonBrightness.setTargetLocked(preferredBrightness,
|
|
ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
|
|
Power.BRIGHTNESS_OFF);
|
|
}
|
|
startAnimation = true;
|
|
} else {
|
|
if ((newState & BUTTON_BRIGHT_BIT) == 0) {
|
|
offMask |= BUTTON_BRIGHT_BIT;
|
|
} else {
|
|
onMask |= BUTTON_BRIGHT_BIT;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((difference & (SCREEN_ON_BIT | SCREEN_BRIGHT_BIT)) != 0) {
|
|
if (ANIMATE_SCREEN_LIGHTS) {
|
|
int nominalCurrentValue = -1;
|
|
// If there was an actual difference in the light state, then
|
|
// figure out the "ideal" current value based on the previous
|
|
// state. Otherwise, this is a change due to the brightness
|
|
// override, so we want to animate from whatever the current
|
|
// value is.
|
|
if ((realDifference & (SCREEN_ON_BIT | SCREEN_BRIGHT_BIT)) != 0) {
|
|
switch (oldState & (SCREEN_BRIGHT_BIT|SCREEN_ON_BIT)) {
|
|
case SCREEN_BRIGHT_BIT | SCREEN_ON_BIT:
|
|
nominalCurrentValue = preferredBrightness;
|
|
break;
|
|
case SCREEN_ON_BIT:
|
|
nominalCurrentValue = Power.BRIGHTNESS_DIM;
|
|
break;
|
|
case 0:
|
|
nominalCurrentValue = Power.BRIGHTNESS_OFF;
|
|
break;
|
|
case SCREEN_BRIGHT_BIT:
|
|
default:
|
|
// not possible
|
|
nominalCurrentValue = (int)mScreenBrightness.curValue;
|
|
break;
|
|
}
|
|
}
|
|
int brightness = preferredBrightness;
|
|
int steps = ANIM_STEPS;
|
|
if ((newState & SCREEN_BRIGHT_BIT) == 0) {
|
|
// dim or turn off backlight, depending on if the screen is on
|
|
// the scale is because the brightness ramp isn't linear and this biases
|
|
// it so the later parts take longer.
|
|
final float scale = 1.5f;
|
|
float ratio = (((float)Power.BRIGHTNESS_DIM)/preferredBrightness);
|
|
if (ratio > 1.0f) ratio = 1.0f;
|
|
if ((newState & SCREEN_ON_BIT) == 0) {
|
|
if ((oldState & SCREEN_BRIGHT_BIT) != 0) {
|
|
// was bright
|
|
steps = ANIM_STEPS;
|
|
} else {
|
|
// was dim
|
|
steps = (int)(ANIM_STEPS*ratio*scale);
|
|
}
|
|
brightness = Power.BRIGHTNESS_OFF;
|
|
} else {
|
|
if ((oldState & SCREEN_ON_BIT) != 0) {
|
|
// was bright
|
|
steps = (int)(ANIM_STEPS*(1.0f-ratio)*scale);
|
|
} else {
|
|
// was dim
|
|
steps = (int)(ANIM_STEPS*ratio);
|
|
}
|
|
if (mStayOnConditions != 0 && mBatteryService.isPowered(mStayOnConditions)) {
|
|
// If the "stay on while plugged in" option is
|
|
// turned on, then the screen will often not
|
|
// automatically turn off while plugged in. To
|
|
// still have a sense of when it is inactive, we
|
|
// will then count going dim as turning off.
|
|
mScreenOffTime = SystemClock.elapsedRealtime();
|
|
}
|
|
brightness = Power.BRIGHTNESS_DIM;
|
|
}
|
|
}
|
|
long identity = Binder.clearCallingIdentity();
|
|
try {
|
|
mBatteryStats.noteScreenBrightness(brightness);
|
|
} catch (RemoteException e) {
|
|
// Nothing interesting to do.
|
|
} finally {
|
|
Binder.restoreCallingIdentity(identity);
|
|
}
|
|
mScreenBrightness.setTargetLocked(brightness,
|
|
steps, INITIAL_SCREEN_BRIGHTNESS, nominalCurrentValue);
|
|
startAnimation = true;
|
|
} else {
|
|
if ((newState & SCREEN_BRIGHT_BIT) == 0) {
|
|
// dim or turn off backlight, depending on if the screen is on
|
|
if ((newState & SCREEN_ON_BIT) == 0) {
|
|
offMask |= SCREEN_BRIGHT_BIT;
|
|
} else {
|
|
dimMask |= SCREEN_BRIGHT_BIT;
|
|
}
|
|
} else {
|
|
onMask |= SCREEN_BRIGHT_BIT;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (startAnimation) {
|
|
if (mSpew) {
|
|
Log.i(TAG, "Scheduling light animator!");
|
|
}
|
|
mHandler.removeCallbacks(mLightAnimator);
|
|
mHandler.post(mLightAnimator);
|
|
}
|
|
|
|
if (offMask != 0) {
|
|
//Log.i(TAG, "Setting brightess off: " + offMask);
|
|
setLightBrightness(offMask, Power.BRIGHTNESS_OFF);
|
|
}
|
|
if (dimMask != 0) {
|
|
int brightness = Power.BRIGHTNESS_DIM;
|
|
if ((newState & BATTERY_LOW_BIT) != 0 &&
|
|
brightness > Power.BRIGHTNESS_LOW_BATTERY) {
|
|
brightness = Power.BRIGHTNESS_LOW_BATTERY;
|
|
}
|
|
//Log.i(TAG, "Setting brightess dim " + brightness + ": " + offMask);
|
|
setLightBrightness(dimMask, brightness);
|
|
}
|
|
if (onMask != 0) {
|
|
int brightness = getPreferredBrightness();
|
|
if ((newState & BATTERY_LOW_BIT) != 0 &&
|
|
brightness > Power.BRIGHTNESS_LOW_BATTERY) {
|
|
brightness = Power.BRIGHTNESS_LOW_BATTERY;
|
|
}
|
|
//Log.i(TAG, "Setting brightess on " + brightness + ": " + onMask);
|
|
setLightBrightness(onMask, brightness);
|
|
}
|
|
}
|
|
|
|
private void setLightBrightness(int mask, int value) {
|
|
if ((mask & SCREEN_BRIGHT_BIT) != 0) {
|
|
mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BACKLIGHT, value);
|
|
}
|
|
if ((mask & BUTTON_BRIGHT_BIT) != 0) {
|
|
mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS, value);
|
|
}
|
|
if ((mask & KEYBOARD_BRIGHT_BIT) != 0) {
|
|
mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD, value);
|
|
}
|
|
}
|
|
|
|
class BrightnessState {
|
|
final int mask;
|
|
|
|
boolean initialized;
|
|
int targetValue;
|
|
float curValue;
|
|
float delta;
|
|
boolean animating;
|
|
|
|
BrightnessState(int m) {
|
|
mask = m;
|
|
}
|
|
|
|
public void dump(PrintWriter pw, String prefix) {
|
|
pw.println(prefix + "animating=" + animating
|
|
+ " targetValue=" + targetValue
|
|
+ " curValue=" + curValue
|
|
+ " delta=" + delta);
|
|
}
|
|
|
|
void setTargetLocked(int target, int stepsToTarget, int initialValue,
|
|
int nominalCurrentValue) {
|
|
if (!initialized) {
|
|
initialized = true;
|
|
curValue = (float)initialValue;
|
|
}
|
|
targetValue = target;
|
|
delta = (targetValue -
|
|
(nominalCurrentValue >= 0 ? nominalCurrentValue : curValue))
|
|
/ stepsToTarget;
|
|
if (mSpew) {
|
|
String noticeMe = nominalCurrentValue == curValue ? "" : " ******************";
|
|
Log.i(TAG, "Setting target " + mask + ": cur=" + curValue
|
|
+ " target=" + targetValue + " delta=" + delta
|
|
+ " nominalCurrentValue=" + nominalCurrentValue
|
|
+ noticeMe);
|
|
}
|
|
animating = true;
|
|
}
|
|
|
|
boolean stepLocked() {
|
|
if (!animating) return false;
|
|
if (false && mSpew) {
|
|
Log.i(TAG, "Step target " + mask + ": cur=" + curValue
|
|
+ " target=" + targetValue + " delta=" + delta);
|
|
}
|
|
curValue += delta;
|
|
int curIntValue = (int)curValue;
|
|
boolean more = true;
|
|
if (delta == 0) {
|
|
curValue = curIntValue = targetValue;
|
|
more = false;
|
|
} else if (delta > 0) {
|
|
if (curIntValue >= targetValue) {
|
|
curValue = curIntValue = targetValue;
|
|
more = false;
|
|
}
|
|
} else {
|
|
if (curIntValue <= targetValue) {
|
|
curValue = curIntValue = targetValue;
|
|
more = false;
|
|
}
|
|
}
|
|
//Log.i(TAG, "Animating brightess " + curIntValue + ": " + mask);
|
|
setLightBrightness(mask, curIntValue);
|
|
animating = more;
|
|
if (!more) {
|
|
if (mask == SCREEN_BRIGHT_BIT && curIntValue == Power.BRIGHTNESS_OFF) {
|
|
screenOffFinishedAnimatingLocked(mOffBecauseOfUser);
|
|
}
|
|
}
|
|
return more;
|
|
}
|
|
}
|
|
|
|
private class LightAnimator implements Runnable {
|
|
public void run() {
|
|
synchronized (mLocks) {
|
|
long now = SystemClock.uptimeMillis();
|
|
boolean more = mScreenBrightness.stepLocked();
|
|
if (mKeyboardBrightness.stepLocked()) {
|
|
more = true;
|
|
}
|
|
if (mButtonBrightness.stepLocked()) {
|
|
more = true;
|
|
}
|
|
if (more) {
|
|
mHandler.postAtTime(mLightAnimator, now+(1000/60));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private int getPreferredBrightness() {
|
|
try {
|
|
if (mScreenBrightnessOverride >= 0) {
|
|
return mScreenBrightnessOverride;
|
|
}
|
|
final int brightness = Settings.System.getInt(mContext.getContentResolver(),
|
|
SCREEN_BRIGHTNESS);
|
|
// Don't let applications turn the screen all the way off
|
|
return Math.max(brightness, Power.BRIGHTNESS_DIM);
|
|
} catch (SettingNotFoundException snfe) {
|
|
return Power.BRIGHTNESS_ON;
|
|
}
|
|
}
|
|
|
|
boolean screenIsOn() {
|
|
synchronized (mLocks) {
|
|
return (mPowerState & SCREEN_ON_BIT) != 0;
|
|
}
|
|
}
|
|
|
|
boolean screenIsBright() {
|
|
synchronized (mLocks) {
|
|
return (mPowerState & SCREEN_BRIGHT) == SCREEN_BRIGHT;
|
|
}
|
|
}
|
|
|
|
public void userActivityWithForce(long time, boolean noChangeLights, boolean force) {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
|
|
userActivity(time, noChangeLights, OTHER_EVENT, force);
|
|
}
|
|
|
|
public void userActivity(long time, boolean noChangeLights) {
|
|
userActivity(time, noChangeLights, OTHER_EVENT, false);
|
|
}
|
|
|
|
public void userActivity(long time, boolean noChangeLights, int eventType) {
|
|
userActivity(time, noChangeLights, eventType, false);
|
|
}
|
|
|
|
public void userActivity(long time, boolean noChangeLights, int eventType, boolean force) {
|
|
//mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
|
|
|
|
if (((mPokey & POKE_LOCK_IGNORE_CHEEK_EVENTS) != 0)
|
|
&& (eventType == CHEEK_EVENT || eventType == TOUCH_EVENT)) {
|
|
if (false) {
|
|
Log.d(TAG, "dropping cheek or short event mPokey=0x" + Integer.toHexString(mPokey));
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (((mPokey & POKE_LOCK_IGNORE_TOUCH_AND_CHEEK_EVENTS) != 0)
|
|
&& (eventType == TOUCH_EVENT || eventType == TOUCH_UP_EVENT
|
|
|| eventType == LONG_TOUCH_EVENT || eventType == CHEEK_EVENT)) {
|
|
if (false) {
|
|
Log.d(TAG, "dropping touch mPokey=0x" + Integer.toHexString(mPokey));
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
if (false) {
|
|
if (((mPokey & POKE_LOCK_IGNORE_CHEEK_EVENTS) != 0)) {
|
|
Log.d(TAG, "userActivity !!!");//, new RuntimeException());
|
|
} else {
|
|
Log.d(TAG, "mPokey=0x" + Integer.toHexString(mPokey));
|
|
}
|
|
}
|
|
|
|
synchronized (mLocks) {
|
|
if (mSpew) {
|
|
Log.d(TAG, "userActivity mLastEventTime=" + mLastEventTime + " time=" + time
|
|
+ " mUserActivityAllowed=" + mUserActivityAllowed
|
|
+ " mUserState=0x" + Integer.toHexString(mUserState)
|
|
+ " mWakeLockState=0x" + Integer.toHexString(mWakeLockState));
|
|
}
|
|
if (mLastEventTime <= time || force) {
|
|
mLastEventTime = time;
|
|
if (mUserActivityAllowed || force) {
|
|
// Only turn on button backlights if a button was pressed.
|
|
if (eventType == BUTTON_EVENT) {
|
|
mUserState = (mKeyboardVisible ? ALL_BRIGHT : SCREEN_BUTTON_BRIGHT);
|
|
} else {
|
|
// don't clear button/keyboard backlights when the screen is touched.
|
|
mUserState |= SCREEN_BRIGHT;
|
|
}
|
|
|
|
int uid = Binder.getCallingUid();
|
|
long ident = Binder.clearCallingIdentity();
|
|
try {
|
|
mBatteryStats.noteUserActivity(uid, eventType);
|
|
} catch (RemoteException e) {
|
|
// Ignore
|
|
} finally {
|
|
Binder.restoreCallingIdentity(ident);
|
|
}
|
|
|
|
reactivateWakeLocksLocked();
|
|
mWakeLockState = mLocks.gatherState();
|
|
setPowerState(mUserState | mWakeLockState, noChangeLights, true);
|
|
setTimeoutLocked(time, SCREEN_BRIGHT);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The user requested that we go to sleep (probably with the power button).
|
|
* This overrides all wake locks that are held.
|
|
*/
|
|
public void goToSleep(long time)
|
|
{
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
|
|
synchronized (mLocks) {
|
|
goToSleepLocked(time);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the time the screen has been on since boot, in millis.
|
|
* @return screen on time
|
|
*/
|
|
public long getScreenOnTime() {
|
|
synchronized (mLocks) {
|
|
if (mScreenOnStartTime == 0) {
|
|
return mScreenOnTime;
|
|
} else {
|
|
return SystemClock.elapsedRealtime() - mScreenOnStartTime + mScreenOnTime;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void goToSleepLocked(long time) {
|
|
|
|
if (mLastEventTime <= time) {
|
|
mLastEventTime = time;
|
|
// cancel all of the wake locks
|
|
mWakeLockState = SCREEN_OFF;
|
|
int N = mLocks.size();
|
|
int numCleared = 0;
|
|
for (int i=0; i<N; i++) {
|
|
WakeLock wl = mLocks.get(i);
|
|
if (isScreenLock(wl.flags)) {
|
|
mLocks.get(i).activated = false;
|
|
numCleared++;
|
|
}
|
|
}
|
|
EventLog.writeEvent(LOG_POWER_SLEEP_REQUESTED, numCleared);
|
|
mStillNeedSleepNotification = true;
|
|
mUserState = SCREEN_OFF;
|
|
setPowerState(SCREEN_OFF, false, true);
|
|
cancelTimerLocked();
|
|
}
|
|
}
|
|
|
|
public long timeSinceScreenOn() {
|
|
synchronized (mLocks) {
|
|
if ((mPowerState & SCREEN_ON_BIT) != 0) {
|
|
return 0;
|
|
}
|
|
return SystemClock.elapsedRealtime() - mScreenOffTime;
|
|
}
|
|
}
|
|
|
|
public void setKeyboardVisibility(boolean visible) {
|
|
mKeyboardVisible = visible;
|
|
}
|
|
|
|
/**
|
|
* When the keyguard is up, it manages the power state, and userActivity doesn't do anything.
|
|
*/
|
|
public void enableUserActivity(boolean enabled) {
|
|
synchronized (mLocks) {
|
|
mUserActivityAllowed = enabled;
|
|
mLastEventTime = SystemClock.uptimeMillis(); // we might need to pass this in
|
|
}
|
|
}
|
|
|
|
/** Sets the screen off timeouts:
|
|
* mKeylightDelay
|
|
* mDimDelay
|
|
* mScreenOffDelay
|
|
* */
|
|
private void setScreenOffTimeoutsLocked() {
|
|
if ((mPokey & POKE_LOCK_SHORT_TIMEOUT) != 0) {
|
|
mKeylightDelay = mShortKeylightDelay; // Configurable via Gservices
|
|
mDimDelay = -1;
|
|
mScreenOffDelay = 0;
|
|
} else if ((mPokey & POKE_LOCK_MEDIUM_TIMEOUT) != 0) {
|
|
mKeylightDelay = MEDIUM_KEYLIGHT_DELAY;
|
|
mDimDelay = -1;
|
|
mScreenOffDelay = 0;
|
|
} else {
|
|
int totalDelay = mTotalDelaySetting;
|
|
mKeylightDelay = LONG_KEYLIGHT_DELAY;
|
|
if (totalDelay < 0) {
|
|
mScreenOffDelay = Integer.MAX_VALUE;
|
|
} else if (mKeylightDelay < totalDelay) {
|
|
// subtract the time that the keylight delay. This will give us the
|
|
// remainder of the time that we need to sleep to get the accurate
|
|
// screen off timeout.
|
|
mScreenOffDelay = totalDelay - mKeylightDelay;
|
|
} else {
|
|
mScreenOffDelay = 0;
|
|
}
|
|
if (mDimScreen && totalDelay >= (LONG_KEYLIGHT_DELAY + LONG_DIM_TIME)) {
|
|
mDimDelay = mScreenOffDelay - LONG_DIM_TIME;
|
|
mScreenOffDelay = LONG_DIM_TIME;
|
|
} else {
|
|
mDimDelay = -1;
|
|
}
|
|
}
|
|
if (mSpew) {
|
|
Log.d(TAG, "setScreenOffTimeouts mKeylightDelay=" + mKeylightDelay
|
|
+ " mDimDelay=" + mDimDelay + " mScreenOffDelay=" + mScreenOffDelay
|
|
+ " mDimScreen=" + mDimScreen);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Refreshes cached Gservices settings. Called once on startup, and
|
|
* on subsequent Settings.Gservices.CHANGED_ACTION broadcasts (see
|
|
* GservicesChangedReceiver).
|
|
*/
|
|
private void updateGservicesValues() {
|
|
mShortKeylightDelay = Settings.Gservices.getInt(
|
|
mContext.getContentResolver(),
|
|
Settings.Gservices.SHORT_KEYLIGHT_DELAY_MS,
|
|
SHORT_KEYLIGHT_DELAY_DEFAULT);
|
|
// Log.i(TAG, "updateGservicesValues(): mShortKeylightDelay now " + mShortKeylightDelay);
|
|
}
|
|
|
|
/**
|
|
* Receiver for the Gservices.CHANGED_ACTION broadcast intent,
|
|
* which tells us we need to refresh our cached Gservices settings.
|
|
*/
|
|
private class GservicesChangedReceiver extends BroadcastReceiver {
|
|
@Override
|
|
public void onReceive(Context context, Intent intent) {
|
|
// Log.i(TAG, "GservicesChangedReceiver.onReceive(): " + intent);
|
|
updateGservicesValues();
|
|
}
|
|
}
|
|
|
|
private class LockList extends ArrayList<WakeLock>
|
|
{
|
|
void addLock(WakeLock wl)
|
|
{
|
|
int index = getIndex(wl.binder);
|
|
if (index < 0) {
|
|
this.add(wl);
|
|
}
|
|
}
|
|
|
|
WakeLock removeLock(IBinder binder)
|
|
{
|
|
int index = getIndex(binder);
|
|
if (index >= 0) {
|
|
return this.remove(index);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
int getIndex(IBinder binder)
|
|
{
|
|
int N = this.size();
|
|
for (int i=0; i<N; i++) {
|
|
if (this.get(i).binder == binder) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int gatherState()
|
|
{
|
|
int result = 0;
|
|
int N = this.size();
|
|
for (int i=0; i<N; i++) {
|
|
WakeLock wl = this.get(i);
|
|
if (wl.activated) {
|
|
if (isScreenLock(wl.flags)) {
|
|
result |= wl.minState;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
void setPolicy(WindowManagerPolicy p) {
|
|
synchronized (mLocks) {
|
|
mPolicy = p;
|
|
mLocks.notifyAll();
|
|
}
|
|
}
|
|
|
|
WindowManagerPolicy getPolicyLocked() {
|
|
while (mPolicy == null || !mDoneBooting) {
|
|
try {
|
|
mLocks.wait();
|
|
} catch (InterruptedException e) {
|
|
// Ignore
|
|
}
|
|
}
|
|
return mPolicy;
|
|
}
|
|
|
|
void systemReady() {
|
|
synchronized (mLocks) {
|
|
Log.d(TAG, "system ready!");
|
|
mDoneBooting = true;
|
|
long identity = Binder.clearCallingIdentity();
|
|
try {
|
|
mBatteryStats.noteScreenBrightness(getPreferredBrightness());
|
|
mBatteryStats.noteScreenOn();
|
|
} catch (RemoteException e) {
|
|
// Nothing interesting to do.
|
|
} finally {
|
|
Binder.restoreCallingIdentity(identity);
|
|
}
|
|
userActivity(SystemClock.uptimeMillis(), false, BUTTON_EVENT, true);
|
|
updateWakeLockLocked();
|
|
mLocks.notifyAll();
|
|
}
|
|
}
|
|
|
|
public void monitor() {
|
|
synchronized (mLocks) { }
|
|
}
|
|
}
|