am e4e71e1d: am 194b6e97: Merge "Power manager rewrite." into jb-mr1-dev

* commit 'e4e71e1d06442726e23f8ccf66c75468634008c4':
  Power manager rewrite.
This commit is contained in:
Jeff Brown
2012-08-15 10:30:52 -07:00
committed by Android Git Automerger
38 changed files with 4839 additions and 3487 deletions

View File

@@ -16273,6 +16273,7 @@ package android.os {
method public android.os.PowerManager.WakeLock newWakeLock(int, java.lang.String);
method public void reboot(java.lang.String);
method public void userActivity(long, boolean);
method public void wakeUp(long);
field public static final int ACQUIRE_CAUSES_WAKEUP = 268435456; // 0x10000000
field public static final deprecated int FULL_WAKE_LOCK = 26; // 0x1a
field public static final int ON_AFTER_RELEASE = 536870912; // 0x20000000
@@ -18763,7 +18764,7 @@ package android.provider {
field public static final android.net.Uri DEFAULT_NOTIFICATION_URI;
field public static final android.net.Uri DEFAULT_RINGTONE_URI;
field public static final deprecated java.lang.String DEVICE_PROVISIONED = "device_provisioned";
field public static final java.lang.String DIM_SCREEN = "dim_screen";
field public static final deprecated java.lang.String DIM_SCREEN = "dim_screen";
field public static final java.lang.String DTMF_TONE_WHEN_DIALING = "dtmf_tone";
field public static final java.lang.String END_BUTTON_BEHAVIOR = "end_button_behavior";
field public static final java.lang.String FONT_SCALE = "font_scale";

View File

@@ -64,7 +64,7 @@ public class PowerCommand extends Svc.Command {
= IPowerManager.Stub.asInterface(ServiceManager.getService(Context.POWER_SERVICE));
try {
IBinder lock = new Binder();
pm.acquireWakeLock(PowerManager.FULL_WAKE_LOCK, lock, "svc power", null);
pm.acquireWakeLock(lock, PowerManager.FULL_WAKE_LOCK, "svc power", null);
pm.setStayOnSetting(val);
pm.releaseWakeLock(lock, 0);
}

View File

@@ -418,7 +418,8 @@ class ContextImpl extends Context {
public Object createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(POWER_SERVICE);
IPowerManager service = IPowerManager.Stub.asInterface(b);
return new PowerManager(service, ctx.mMainThread.getHandler());
return new PowerManager(ctx.getOuterContext(),
service, ctx.mMainThread.getHandler());
}});
registerService(SEARCH_SERVICE, new ServiceFetcher() {

View File

@@ -23,27 +23,33 @@ import android.os.WorkSource;
interface IPowerManager
{
// WARNING: changes in acquireWakeLock() signature must be reflected in IPowerManager.cpp/h
void acquireWakeLock(int flags, IBinder lock, String tag, in WorkSource ws);
void updateWakeLockWorkSource(IBinder lock, in WorkSource ws);
void goToSleep(long time);
void goToSleepWithReason(long time, int reason);
// WARNING: changes in releaseWakeLock() signature must be reflected in IPowerManager.cpp/h
// WARNING: The first two methods must remain the first two methods because their
// transaction numbers must not change unless IPowerManager.cpp is also updated.
void acquireWakeLock(IBinder lock, int flags, String tag, in WorkSource ws);
void releaseWakeLock(IBinder lock, int flags);
void userActivity(long when, boolean noChangeLights);
void userActivityWithForce(long when, boolean noChangeLights, boolean force);
void clearUserActivityTimeout(long now, long timeout);
void setPokeLock(int pokey, IBinder lock, String tag);
int getSupportedWakeLockFlags();
void setStayOnSetting(int val);
void setMaximumScreenOffTimeount(int timeMs);
void preventScreenOn(boolean prevent);
void updateWakeLockWorkSource(IBinder lock, in WorkSource ws);
boolean isWakeLockLevelSupported(int level);
void userActivity(long time, int event, int flags);
void wakeUp(long time);
void goToSleep(long time, int reason);
boolean isScreenOn();
void reboot(String reason);
void crash(String message);
// sets the brightness of the backlights (screen, keyboard, button) 0-255
void setBacklightBrightness(int brightness);
void clearUserActivityTimeout(long now, long timeout);
void setPokeLock(int pokey, IBinder lock, String tag);
void setStayOnSetting(int val);
void setMaximumScreenOffTimeoutFromDeviceAdmin(int timeMs);
void preventScreenOn(boolean prevent);
// temporarily overrides the screen brightness settings to allow the user to
// see the effect of a settings change without applying it immediately
void setTemporaryScreenBrightnessSettingOverride(int brightness);
void setTemporaryScreenAutoBrightnessAdjustmentSettingOverride(float adj);
// sets the attention light (used by phone app only)
void setAttentionLight(boolean on, int color);
void setAutoBrightnessAdjustment(float adj);
}

View File

@@ -18,25 +18,11 @@ package android.os;
/** @hide */
public interface LocalPowerManager {
// FIXME: Replace poke locks with something else.
public static final int POKE_LOCK_IGNORE_TOUCH_EVENTS = 0x1;
public static final int POKE_LOCK_SHORT_TIMEOUT = 0x2;
public static final int POKE_LOCK_MEDIUM_TIMEOUT = 0x4;
public static final int POKE_LOCK_TIMEOUT_MASK = 0x6;
void goToSleep(long time);
// notify power manager when keyboard is opened/closed
void setKeyboardVisibility(boolean visible);
// when the keyguard is up, it manages the power state, and userActivity doesn't do anything.
void enableUserActivity(boolean enabled);
// the same as the method on PowerManager
void userActivity(long time, boolean noChangeLights, int eventType);
boolean isScreenOn();
void setScreenBrightnessOverride(int brightness);
void setButtonBrightnessOverride(int brightness);
}

View File

@@ -16,6 +16,7 @@
package android.os;
import android.content.Context;
import android.util.Log;
/**
@@ -42,8 +43,8 @@ import android.util.Log;
* wl.release();
* }
* </p><p>
* The following flags are defined, with varying effects on system power.
* <i>These flags are mutually exclusive - you may only specify one of them.</i>
* The following wake lock levels are defined, with varying effects on system power.
* <i>These levels are mutually exclusive - you may only specify one of them.</i>
*
* <table border="2" width="85%" align="center" frame="hsides" rules="rows">
* <thead>
@@ -177,7 +178,7 @@ public final class PowerManager {
/**
* Wake lock level: Turns the screen off when the proximity sensor activates.
* <p>
* Since not all devices have proximity sensors, use {@link #getSupportedWakeLockFlags}
* Since not all devices have proximity sensors, use {@link #isWakeLockLevelSupported}
* to determine whether this wake lock level is supported.
* </p>
*
@@ -226,30 +227,25 @@ public final class PowerManager {
*/
public static final int WAIT_FOR_PROXIMITY_NEGATIVE = 1;
/**
* Brightness value to use when battery is low.
* @hide
*/
public static final int BRIGHTNESS_LOW_BATTERY = 10;
/**
* Brightness value for fully on.
* @hide
*/
public static final int BRIGHTNESS_ON = 255;
/**
* Brightness value for dim backlight.
* @hide
*/
public static final int BRIGHTNESS_DIM = 20;
/**
* Brightness value for fully off.
* @hide
*/
public static final int BRIGHTNESS_OFF = 0;
/**
* A nominal default brightness value.
* Use {@link #getDefaultScreenBrightnessSetting()} instead.
* @hide
*/
private static final int BRIGHTNESS_DEFAULT = 102;
// Note: Be sure to update android.os.BatteryStats and PowerManager.h
// if adding or modifying user activity event constants.
@@ -271,17 +267,81 @@ public final class PowerManager {
*/
public static final int USER_ACTIVITY_EVENT_TOUCH = 2;
/**
* User activity flag: Do not restart the user activity timeout or brighten
* the display in response to user activity if it is already dimmed.
* @hide
*/
public static final int USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS = 1 << 0;
/**
* Special wake lock tag used for the wake lock in the Window Manager that handles the
* {@link android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON} flag.
* @hide
*/
public static final String KEEP_SCREEN_ON_FLAG_TAG = "KEEP_SCREEN_ON_FLAG";
/**
* Go to sleep reason code: Going to sleep due by user request.
* @hide
*/
public static final int GO_TO_SLEEP_REASON_USER = 0;
/**
* Go to sleep reason code: Going to sleep due by request of the
* device administration policy.
* @hide
*/
public static final int GO_TO_SLEEP_REASON_DEVICE_ADMIN = 1;
/**
* Go to sleep reason code: Going to sleep due to a screen timeout.
* @hide
*/
public static final int GO_TO_SLEEP_REASON_TIMEOUT = 2;
final Context mContext;
final IPowerManager mService;
final Handler mHandler;
/**
* {@hide}
*/
public PowerManager(IPowerManager service, Handler handler) {
public PowerManager(Context context, IPowerManager service, Handler handler) {
mContext = context;
mService = service;
mHandler = handler;
}
/**
* Gets the minimum supported screen brightness setting.
* The screen may be allowed to become dimmer than this value but
* this is the minimum value that can be set by the user.
* @hide
*/
public int getMinimumScreenBrightnessSetting() {
return mContext.getResources().getInteger(
com.android.internal.R.integer.config_screenBrightnessDim);
}
/**
* Gets the maximum supported screen brightness setting.
* The screen may be allowed to become dimmer than this value but
* this is the maximum value that can be set by the user.
* @hide
*/
public int getMaximumScreenBrightnessSetting() {
return BRIGHTNESS_ON;
}
/**
* Gets the default screen brightness setting.
* @hide
*/
public int getDefaultScreenBrightnessSetting() {
return BRIGHTNESS_DEFAULT;
}
/**
* Creates a new wake lock with the specified level and flags.
* <p>
@@ -360,8 +420,10 @@ public final class PowerManager {
/**
* Notifies the power manager that user activity happened.
* <p>
* Turns the device from whatever state it's in to full on, and resets
* the auto-off timer.
* Resets the auto-off timer and brightens the screen if the device
* is not asleep. This is what happens normally when a key or the touch
* screen is pressed or when some other user activity occurs.
* This method does not wake up the device if it has been put to sleep.
* </p><p>
* Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
* </p>
@@ -375,10 +437,14 @@ public final class PowerManager {
* We want the device to stay on while the button is down, but we're about
* to turn off the screen so we don't want the keyboard backlight to turn on again.
* Otherwise the lights flash on and then off and it looks weird.
*
* @see #wakeUp
* @see #goToSleep
*/
public void userActivity(long when, boolean noChangeLights) {
try {
mService.userActivity(when, noChangeLights);
mService.userActivity(when, USER_ACTIVITY_EVENT_OTHER,
noChangeLights ? USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS : 0);
} catch (RemoteException e) {
}
}
@@ -386,8 +452,8 @@ public final class PowerManager {
/**
* Forces the device to go to sleep.
* <p>
* Overrides all the wake locks that are held. This is what happen when the power
* key is pressed to turn off the screen.
* Overrides all the wake locks that are held.
* This is what happens when the power key is pressed to turn off the screen.
* </p><p>
* Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
* </p>
@@ -396,10 +462,37 @@ public final class PowerManager {
* {@link SystemClock#uptimeMillis()} time base. This timestamp is used to correctly
* order the user activity with other power management functions. It should be set
* to the timestamp of the input event that caused the request to go to sleep.
*
* @see #userActivity
* @see #wakeUp
*/
public void goToSleep(long time) {
try {
mService.goToSleep(time);
mService.goToSleep(time, GO_TO_SLEEP_REASON_USER);
} catch (RemoteException e) {
}
}
/**
* Forces the device to wake up from sleep.
* <p>
* If the device is currently asleep, wakes it up, otherwise does nothing.
* This is what happens when the power key is pressed to turn on the screen.
* </p><p>
* Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
* </p>
*
* @param time The time when the request to wake up was issued, in the
* {@link SystemClock#uptimeMillis()} time base. This timestamp is used to correctly
* order the user activity with other power management functions. It should be set
* to the timestamp of the input event that caused the request to wake up.
*
* @see #userActivity
* @see #goToSleep
*/
public void wakeUp(long time) {
try {
mService.wakeUp(time);
} catch (RemoteException e) {
}
}
@@ -416,34 +509,24 @@ public final class PowerManager {
*/
public void setBacklightBrightness(int brightness) {
try {
mService.setBacklightBrightness(brightness);
mService.setTemporaryScreenBrightnessSettingOverride(brightness);
} catch (RemoteException e) {
}
}
/**
* Returns the set of wake lock levels and flags for {@link #newWakeLock}
* that are supported on the device.
* <p>
* For example, to test to see if the {@link #PROXIMITY_SCREEN_OFF_WAKE_LOCK}
* is supported:
* {@samplecode
* PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
* int supportedFlags = pm.getSupportedWakeLockFlags();
* boolean proximitySupported = ((supportedFlags & PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)
* == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK);
* }
* </p>
* Returns true if the specified wake lock level is supported.
*
* @return The set of supported WakeLock flags.
* @param level The wake lock level to check.
* @return True if the specified wake lock level is supported.
*
* {@hide}
*/
public int getSupportedWakeLockFlags() {
public boolean isWakeLockLevelSupported(int level) {
try {
return mService.getSupportedWakeLockFlags();
return mService.isWakeLockLevelSupported(level);
} catch (RemoteException e) {
return 0;
return false;
}
}
@@ -593,7 +676,7 @@ public final class PowerManager {
// been explicitly released by the keyguard.
mHandler.removeCallbacks(mReleaser);
try {
mService.acquireWakeLock(mFlags, mToken, mTag, mWorkSource);
mService.acquireWakeLock(mToken, mFlags, mTag, mWorkSource);
} catch (RemoteException e) {
}
mHeld = true;

View File

@@ -1,5 +1,9 @@
package android.os;
import com.android.internal.util.ArrayUtils;
import java.util.Arrays;
/**
* Describes the source of some work that may be done by someone else.
* Currently the public representation of what a work source is is not
@@ -313,6 +317,20 @@ public class WorkSource implements Parcelable {
dest.writeIntArray(mUids);
}
@Override
public String toString() {
StringBuilder result = new StringBuilder();
result.append("{WorkSource: uids=[");
for (int i = 0; i < mNum; i++) {
if (i != 0) {
result.append(", ");
}
result.append(mUids[i]);
}
result.append("]}");
return result.toString();
}
public static final Parcelable.Creator<WorkSource> CREATOR
= new Parcelable.Creator<WorkSource>() {
public WorkSource createFromParcel(Parcel in) {

View File

@@ -1381,7 +1381,9 @@ public final class Settings {
/**
* Whether or not to dim the screen. 0=no 1=yes
* @deprecated This setting is no longer used.
*/
@Deprecated
public static final String DIM_SCREEN = "dim_screen";
/**

View File

@@ -123,7 +123,9 @@ public class DreamManagerService
// IDreamManager method
@Override
public boolean isDreaming() {
return mCurrentDream != null;
synchronized (mLock) {
return mCurrentDreamToken != null;
}
}
public void bindDreamComponentL(ComponentName componentName, boolean test) {

View File

@@ -18,6 +18,7 @@ package android.util;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.os.SystemClock;
import android.text.format.DateUtils;
import com.android.internal.util.XmlUtils;
@@ -391,6 +392,18 @@ public class TimeUtils {
formatDuration(time-now, pw, 0);
}
/** @hide Just for debugging; not internationalized. */
public static String formatUptime(long time) {
final long diff = time - SystemClock.uptimeMillis();
if (diff > 0) {
return time + " (in " + diff + " ms)";
}
if (diff < 0) {
return time + " (" + -diff + " ms ago)";
}
return time + " (now)";
}
/**
* Convert a System.currentTimeMillis() value to a time of day value like
* that printed in logs. MM-DD HH:MM:SS.MMM

View File

@@ -22,7 +22,6 @@ import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.IBinder;
import android.os.LocalPowerManager;
import android.os.Looper;
import android.view.animation.Animation;
@@ -115,11 +114,11 @@ public interface WindowManagerPolicy {
public final static int ACTION_PASS_TO_USER = 0x00000001;
/**
* This key event should extend the user activity timeout and turn the lights on.
* This key event should wake the device.
* To be returned from {@link #interceptKeyBeforeQueueing}.
* Do not return this and {@link #ACTION_GO_TO_SLEEP} or {@link #ACTION_PASS_TO_USER}.
*/
public final static int ACTION_POKE_USER_ACTIVITY = 0x00000002;
public final static int ACTION_WAKE_UP = 0x00000002;
/**
* This key event should put the device to sleep (and engage keyguard if necessary)
@@ -473,11 +472,9 @@ public interface WindowManagerPolicy {
* Perform initialization of the policy.
*
* @param context The system context we are running in.
* @param powerManager
*/
public void init(Context context, IWindowManager windowManager,
WindowManagerFuncs windowManagerFuncs,
LocalPowerManager powerManager);
WindowManagerFuncs windowManagerFuncs);
/**
* Called by window manager once it has the initial, default native
@@ -1092,31 +1089,6 @@ public interface WindowManagerPolicy {
*/
public void lockNow();
/**
* Check to see if a screensaver should be run instead of powering off the screen on timeout.
*
* @return true if the screensaver should run, false if the screen should turn off.
*
* @hide
*/
public boolean isScreenSaverEnabled();
/**
* Start the screensaver (if it is enabled and not yet running).
*
* @return Whether the screensaver was successfully started.
*
* @hide
*/
public boolean startScreenSaver();
/**
* Stop the screensaver if it is running.
*
* @hide
*/
public void stopScreenSaver();
/**
* Set the last used input method window state. This state is used to make IME transition
* smooth.

View File

@@ -500,19 +500,15 @@ public class ConnectivityManagerTestActivity extends Activity {
log("Turn screen off");
PowerManager pm =
(PowerManager) getSystemService(Context.POWER_SERVICE);
pm.goToSleep(SystemClock.uptimeMillis() + 100);
pm.goToSleep(SystemClock.uptimeMillis());
}
// Turn screen on
public void turnScreenOn() {
log("Turn screen on");
IPowerManager mPowerManagerService = IPowerManager.Stub.asInterface(
ServiceManager.getService("power"));;
try {
mPowerManagerService.userActivityWithForce(SystemClock.uptimeMillis(), false, true);
} catch (Exception e) {
log(e.toString());
}
PowerManager pm =
(PowerManager) getSystemService(Context.POWER_SERVICE);
pm.wakeUp(SystemClock.uptimeMillis());
}
/**

View File

@@ -49,7 +49,7 @@ public class BrightnessLimit extends Activity implements OnClickListener {
ServiceManager.getService("power"));
if (power != null) {
try {
power.setBacklightBrightness(0);
power.setTemporaryScreenBrightnessSettingOverride(0);
} catch (RemoteException darn) {
}

View File

@@ -109,7 +109,7 @@ public class SettingsHelper {
IPowerManager power = IPowerManager.Stub.asInterface(
ServiceManager.getService("power"));
if (power != null) {
power.setBacklightBrightness(brightness);
power.setTemporaryScreenBrightnessSettingOverride(brightness);
}
} catch (RemoteException doe) {

View File

@@ -20,6 +20,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.os.AsyncTask;
import android.os.IPowerManager;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;
@@ -31,8 +32,8 @@ import android.widget.CompoundButton;
public class BrightnessController implements ToggleSlider.Listener {
private static final String TAG = "StatusBar.BrightnessController";
private static final int MINIMUM_BACKLIGHT = android.os.PowerManager.BRIGHTNESS_DIM;
private static final int MAXIMUM_BACKLIGHT = android.os.PowerManager.BRIGHTNESS_ON;
private final int mMinimumBacklight;
private final int mMaximumBacklight;
private Context mContext;
private ToggleSlider mControl;
@@ -42,6 +43,10 @@ public class BrightnessController implements ToggleSlider.Listener {
mContext = context;
mControl = control;
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mMinimumBacklight = pm.getMinimumScreenBrightnessSetting();
mMaximumBacklight = pm.getMaximumScreenBrightnessSetting();
boolean automaticAvailable = context.getResources().getBoolean(
com.android.internal.R.bool.config_automatic_brightness_available);
mPower = IPowerManager.Stub.asInterface(ServiceManager.getService("power"));
@@ -65,11 +70,11 @@ public class BrightnessController implements ToggleSlider.Listener {
value = Settings.System.getInt(mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS);
} catch (SettingNotFoundException ex) {
value = MAXIMUM_BACKLIGHT;
value = mMaximumBacklight;
}
control.setMax(MAXIMUM_BACKLIGHT - MINIMUM_BACKLIGHT);
control.setValue(value - MINIMUM_BACKLIGHT);
control.setMax(mMaximumBacklight - mMinimumBacklight);
control.setValue(value - mMinimumBacklight);
control.setOnChangedListener(this);
}
@@ -78,7 +83,7 @@ public class BrightnessController implements ToggleSlider.Listener {
setMode(automatic ? Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC
: Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
if (!automatic) {
final int val = value + MINIMUM_BACKLIGHT;
final int val = value + mMinimumBacklight;
setBrightness(val);
if (!tracking) {
AsyncTask.execute(new Runnable() {
@@ -98,7 +103,7 @@ public class BrightnessController implements ToggleSlider.Listener {
private void setBrightness(int brightness) {
try {
mPower.setBacklightBrightness(brightness);
mPower.setTemporaryScreenBrightnessSettingOverride(brightness);
} catch (RemoteException ex) {
}
}

View File

@@ -33,7 +33,6 @@ import android.content.IntentFilter;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Handler;
import android.os.LocalPowerManager;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
@@ -157,10 +156,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback {
private boolean mSuppressNextLockSound = true;
/** Low level access to the power manager for enableUserActivity. Having this
* requires that we run in the system process. */
LocalPowerManager mRealPowerManager;
/** High level access to the power manager for WakeLocks */
private PowerManager mPM;
@@ -358,11 +353,9 @@ public class KeyguardViewMediator implements KeyguardViewCallback {
};
public KeyguardViewMediator(Context context, PhoneWindowManager callback,
LocalPowerManager powerManager) {
public KeyguardViewMediator(Context context, PhoneWindowManager callback) {
mContext = context;
mCallback = callback;
mRealPowerManager = powerManager;
mPM = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mWakeLock = mPM.newWakeLock(
PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "keyguard");
@@ -1034,7 +1027,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback {
if (DEBUG) Log.d(TAG, "handleKeyguardDone");
handleHide();
if (wakeup) {
mPM.userActivity(SystemClock.uptimeMillis(), true);
mPM.wakeUp(SystemClock.uptimeMillis());
}
mWakeLock.release();
mContext.sendBroadcast(mUserPresentIntent);
@@ -1167,7 +1160,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback {
// disable user activity if we are shown and not hidden
if (DEBUG) Log.d(TAG, "adjustUserActivityLocked mShowing: " + mShowing + " mHidden: " + mHidden);
boolean enabled = !mShowing || mHidden;
mRealPowerManager.enableUserActivity(enabled);
// FIXME: Replace this with a new timeout control mechanism.
//mRealPowerManager.enableUserActivity(enabled);
if (!enabled && mScreenOn) {
// reinstate our short screen timeout policy
pokeWakelock();

View File

@@ -45,7 +45,6 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.LocalPowerManager;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
@@ -170,9 +169,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
static final boolean ENABLE_CAR_DOCK_HOME_CAPTURE = true;
static final boolean ENABLE_DESK_DOCK_HOME_CAPTURE = false;
// Should screen savers use their own timeout, or the SCREEN_OFF_TIMEOUT?
static final boolean SEPARATE_TIMEOUT_FOR_SCREEN_SAVER = false;
static final int LONG_PRESS_POWER_NOTHING = 0;
static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1;
static final int LONG_PRESS_POWER_SHUT_OFF = 2;
@@ -280,7 +276,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
Context mContext;
IWindowManager mWindowManager;
WindowManagerFuncs mWindowManagerFuncs;
LocalPowerManager mPowerManager;
PowerManager mPowerManager;
IStatusBarService mStatusBarService;
final Object mServiceAquireLock = new Object();
Vibrator mVibrator; // Vibrator for giving feedback of orientation changes
@@ -474,13 +470,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
int mLockScreenTimeout;
boolean mLockScreenTimerActive;
// visual screen saver support
boolean mScreenSaverFeatureAvailable;
int mScreenSaverTimeout = 0;
boolean mScreenSaverEnabledByUser = false;
boolean mScreenSaverMayRun = true; // false if a wakelock is held
boolean mPluggedIn;
// Behavior of ENDCALL Button. (See Settings.System.END_BUTTON_BEHAVIOR.)
int mEndcallBehavior;
@@ -572,12 +561,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
Settings.Secure.DEFAULT_INPUT_METHOD), false, this);
resolver.registerContentObserver(Settings.System.getUriFor(
"fancy_rotation_anim"), false, this);
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.SCREENSAVER_ENABLED), false, this);
if (SEPARATE_TIMEOUT_FOR_SCREEN_SAVER) {
resolver.registerContentObserver(Settings.Secure.getUriFor(
"screensaver_timeout"), false, this);
} // otherwise SCREEN_OFF_TIMEOUT will do nicely
updateSettings();
}
@@ -863,16 +846,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
/** {@inheritDoc} */
public void init(Context context, IWindowManager windowManager,
WindowManagerFuncs windowManagerFuncs,
LocalPowerManager powerManager) {
WindowManagerFuncs windowManagerFuncs) {
mContext = context;
mWindowManager = windowManager;
mWindowManagerFuncs = windowManagerFuncs;
mPowerManager = powerManager;
mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
if (!mHeadless) {
// don't create KeyguardViewMediator if headless
mKeyguardMediator = new KeyguardViewMediator(context, this, powerManager);
mKeyguardMediator = new KeyguardViewMediator(context, this);
}
mHandler = new PolicyHandler();
mOrientationListener = new MyOrientationListener(mContext);
@@ -898,8 +879,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mDeskDockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mBroadcastWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mBroadcastWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"PhoneWindowManager.mBroadcastWakeLock");
mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable"));
mLidOpenRotation = readRotation(
@@ -932,14 +913,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
Intent.EXTRA_DOCK_STATE_UNDOCKED);
}
// watch the plug to know whether to trigger the screen saver
filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
intent = context.registerReceiver(mPowerReceiver, filter);
if (intent != null) {
mPluggedIn = (0 != intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0));
}
mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
mLongPressVibePattern = getLongIntArray(mContext.getResources(),
com.android.internal.R.array.config_longPressVibePattern);
@@ -1121,26 +1094,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mHasSoftInput = hasSoftInput;
updateRotation = true;
}
// dreams
mScreenSaverFeatureAvailable = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_enableDreams);
mScreenSaverEnabledByUser = 0 != Settings.Secure.getInt(resolver,
Settings.Secure.SCREENSAVER_ENABLED, 0);
if (SEPARATE_TIMEOUT_FOR_SCREEN_SAVER) {
mScreenSaverTimeout = Settings.Secure.getInt(resolver,
"screensaver_timeout", 0);
} else {
mScreenSaverTimeout = Settings.System.getInt(resolver,
Settings.System.SCREEN_OFF_TIMEOUT, 0);
if (mScreenSaverTimeout > 0) {
// We actually want to activate the screensaver just before the
// power manager's screen timeout
mScreenSaverTimeout -= 5000;
}
}
}
if (updateRotation) {
updateRotation(true);
@@ -3018,12 +2971,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(
KeyEvent.KEYCODE_POWER, mDockMode != Intent.EXTRA_DOCK_STATE_UNDOCKED);
} else {
mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
PowerManager.USER_ACTIVITY_EVENT_BUTTON);
mPowerManager.wakeUp(SystemClock.uptimeMillis());
}
} else if (!mLidControlsSleep) {
mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
PowerManager.USER_ACTIVITY_EVENT_OTHER);
mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
}
}
@@ -3182,6 +3133,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
/** {@inheritDoc} */
@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
if (!mSystemBooted) {
// If we have not yet booted, don't let key events do anything.
return 0;
}
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
final boolean canceled = event.isCanceled();
final int keyCode = event.getKeyCode();
@@ -3197,14 +3153,17 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mKeyguardMediator.isShowingAndNotHidden() :
mKeyguardMediator.isShowing()));
if (!mSystemBooted) {
// If we have not yet booted, don't let key events do anything.
return 0;
if (keyCode == KeyEvent.KEYCODE_POWER) {
policyFlags |= WindowManagerPolicy.FLAG_WAKE;
}
final boolean isWakeKey = (policyFlags & (WindowManagerPolicy.FLAG_WAKE
| WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
if (DEBUG_INPUT) {
Log.d(TAG, "interceptKeyTq keycode=" + keyCode
+ " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive);
+ " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive
+ " policyFlags=" + Integer.toHexString(policyFlags)
+ " isWakeKey=" + isWakeKey);
}
if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0
@@ -3212,12 +3171,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
}
if (keyCode == KeyEvent.KEYCODE_POWER) {
policyFlags |= WindowManagerPolicy.FLAG_WAKE;
}
final boolean isWakeKey = (policyFlags & (WindowManagerPolicy.FLAG_WAKE
| WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
// Basic policy based on screen state and keyguard.
// FIXME: This policy isn't quite correct. We shouldn't care whether the screen
// is on or off, really. We should care about whether the device is in an
@@ -3241,7 +3194,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mDockMode != Intent.EXTRA_DOCK_STATE_UNDOCKED);
} else {
// Otherwise, wake the device ourselves.
result |= ACTION_POKE_USER_ACTIVITY;
result |= ACTION_WAKE_UP;
}
}
}
@@ -3346,7 +3299,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
if ((mEndcallBehavior
& Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
result = (result & ~ACTION_POKE_USER_ACTIVITY) | ACTION_GO_TO_SLEEP;
result = (result & ~ACTION_WAKE_UP) | ACTION_GO_TO_SLEEP;
}
}
}
@@ -3388,7 +3341,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mPowerKeyTriggered = false;
cancelPendingScreenshotChordAction();
if (interceptPowerKeyUp(canceled || mPendingPowerKeyUpCanceled)) {
result = (result & ~ACTION_POKE_USER_ACTIVITY) | ACTION_GO_TO_SLEEP;
result = (result & ~ACTION_WAKE_UP) | ACTION_GO_TO_SLEEP;
}
mPendingPowerKeyUpCanceled = false;
}
@@ -3473,7 +3426,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mKeyguardMediator.onWakeMotionWhenKeyguardShowingTq();
} else {
// Otherwise, wake the device ourselves.
result |= ACTION_POKE_USER_ACTIVITY;
result |= ACTION_WAKE_UP;
}
}
return result;
@@ -3553,15 +3506,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
};
BroadcastReceiver mPowerReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
mPluggedIn = (0 != intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0));
if (localLOGV) Log.v(TAG, "BATTERY_CHANGED: " + intent + " plugged=" + mPluggedIn);
}
}
};
/** {@inheritDoc} */
public void screenTurnedOff(int why) {
EventLog.writeEvent(70000, 0);
@@ -4035,62 +3979,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
private IDreamManager getDreamManager() {
if (!mScreenSaverFeatureAvailable) {
return null;
}
IDreamManager sandman = IDreamManager.Stub.asInterface(
ServiceManager.checkService("dreams"));
if (sandman == null) {
Log.w(TAG, "Unable to find IDreamManager");
}
return sandman;
}
@Override
public boolean isScreenSaverEnabled() {
return (mScreenSaverFeatureAvailable && mScreenSaverEnabledByUser
&& mScreenSaverMayRun && mScreenOnEarly && mPluggedIn);
}
@Override
public boolean startScreenSaver() {
synchronized (mLock) {
if (isScreenSaverEnabled()) {
IDreamManager dm = getDreamManager();
if (dm == null) return false;
try {
if (localLOGV) Log.v(TAG, "startScreenSaver: entering dreamland...");
dm.dream();
return true;
} catch (RemoteException ex) {
// too bad, so sad, oh mom, oh dad
}
}
}
return false;
}
@Override
public void stopScreenSaver() {
synchronized (mLock) {
IDreamManager dm = getDreamManager();
if (dm == null) return;
try {
if (!dm.isDreaming()) return;
if (localLOGV) Log.v(TAG, "stopScreenSaver: awakening...");
dm.awaken();
} catch (RemoteException ex) {
}
}
}
Runnable mScreenLockTimeout = new Runnable() {
public void run() {
synchronized (this) {
@@ -4134,8 +4022,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
private void applyLidSwitchState() {
mPowerManager.setKeyboardVisibility(isBuiltInKeyboardVisible());
if (mLidState == LID_CLOSED && mLidControlsSleep) {
mPowerManager.goToSleep(SystemClock.uptimeMillis());
}
@@ -4317,24 +4203,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
public void screenOnStartedLw() {
// The window manager has just grabbed a wake lock. This is our cue to disable the screen
// saver.
synchronized (mLock) {
mScreenSaverMayRun = false;
}
}
public void screenOnStoppedLw() {
if (mPowerManager.isScreenOn()) {
if (mKeyguardMediator != null && !mKeyguardMediator.isShowingAndNotHidden()) {
long curTime = SystemClock.uptimeMillis();
mPowerManager.userActivity(curTime, false, PowerManager.USER_ACTIVITY_EVENT_OTHER);
}
synchronized (mLock) {
// even if the keyguard is up, now that all the wakelocks have been released, we
// should re-enable the screen saver
mScreenSaverMayRun = true;
mPowerManager.userActivity(curTime, false);
}
}
}

View File

@@ -1626,7 +1626,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mLastMaximumTimeToLock = timeMs;
try {
getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
getIPowerManager().setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs);
} catch (RemoteException e) {
Slog.w(TAG, "Failure talking with power manager", e);
}
@@ -1667,8 +1667,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
long ident = Binder.clearCallingIdentity();
try {
// Power off the display
mIPowerManager.goToSleepWithReason(SystemClock.uptimeMillis(),
WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN);
getIPowerManager().goToSleep(SystemClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN);
// Ensure the device is locked
getWindowManager().lockNow();
} catch (RemoteException e) {

View File

@@ -33,6 +33,7 @@ import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.UEventObserver;
import android.provider.Settings;
@@ -64,11 +65,8 @@ class DockObserver extends UEventObserver {
private final Context mContext;
private PowerManagerService mPowerManager;
public DockObserver(Context context, PowerManagerService pm) {
public DockObserver(Context context) {
mContext = context;
mPowerManager = pm;
init(); // set initial status
startObserving(DOCK_UEVENT_MATCH);
@@ -94,8 +92,9 @@ class DockObserver extends UEventObserver {
&& mPreviousDockState != Intent.EXTRA_DOCK_STATE_LE_DESK
&& mPreviousDockState != Intent.EXTRA_DOCK_STATE_HE_DESK) ||
mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
mPowerManager.userActivityWithForce(SystemClock.uptimeMillis(),
false, true);
PowerManager pm =
(PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
pm.wakeUp(SystemClock.uptimeMillis());
}
update();
}

View File

@@ -50,6 +50,7 @@ import com.android.internal.os.SamplingProfilerIntegration;
import com.android.internal.widget.LockSettingsService;
import com.android.server.accessibility.AccessibilityManagerService;
import com.android.server.am.ActivityManagerService;
import com.android.server.am.BatteryStatsService;
import com.android.server.display.DisplayManagerService;
import com.android.server.input.InputManagerService;
import com.android.server.net.NetworkPolicyManagerService;
@@ -230,7 +231,8 @@ class ServerThread extends Thread {
// only initialize the power service after we have started the
// lights service, content providers and the battery service.
power.init(context, lights, ActivityManagerService.self(), battery, display);
power.init(context, lights, ActivityManagerService.self(), battery,
BatteryStatsService.getService(), display);
Slog.i(TAG, "Alarm Manager");
alarm = new AlarmManagerService(context);
@@ -553,7 +555,7 @@ class ServerThread extends Thread {
try {
Slog.i(TAG, "Dock Observer");
// Listen for dock station changes
dock = new DockObserver(context, power);
dock = new DockObserver(context);
} catch (Throwable e) {
reportWtf("starting DockObserver", e);
}

View File

@@ -349,7 +349,7 @@ public class Watchdog extends Thread {
}
if (mMinScreenOff >= 0 && (mPower == null ||
mPower.timeSinceScreenOn() < mMinScreenOff)) {
mPower.timeSinceScreenWasLastOn() < mMinScreenOff)) {
return "screen";
}

View File

@@ -0,0 +1,992 @@
/*
* Copyright (C) 2012 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.power;
import com.android.server.LightsService;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.SystemSensorManager;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.util.Slog;
import android.util.TimeUtils;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
/**
* Controls the power state of the display.
*
* Handles the proximity sensor, light sensor, and animations between states
* including the screen off animation.
*
* This component acts independently of the rest of the power manager service.
* In particular, it does not share any state and it only communicates
* via asynchronous callbacks to inform the power manager that something has
* changed.
*
* Everything this class does internally is serialized on its handler although
* it may be accessed by other threads from the outside.
*
* Note that the power manager service guarantees that it will hold a suspend
* blocker as long as the display is not ready. So most of the work done here
* does not need to worry about holding a suspend blocker unless it happens
* independently of the display ready signal.
*
* For debugging, you can make the electron beam and brightness animations run
* slower by changing the "animator duration scale" option in Development Settings.
*/
final class DisplayPowerController {
private static final String TAG = "DisplayPowerController";
private static boolean DEBUG = false;
private static final boolean DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT = false;
private static final boolean DEBUG_PRETEND_LIGHT_SENSOR_ABSENT = false;
private static final int ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS = 300;
private static final int ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS = 600;
private static final int MSG_UPDATE_POWER_STATE = 1;
private static final int MSG_PROXIMITY_SENSOR_DEBOUNCED = 2;
private static final int MSG_LIGHT_SENSOR_DEBOUNCED = 3;
private static final int PROXIMITY_UNKNOWN = -1;
private static final int PROXIMITY_NEGATIVE = 0;
private static final int PROXIMITY_POSITIVE = 1;
// Proximity sensor debounce delay in milliseconds.
private static final int PROXIMITY_SENSOR_DEBOUNCE_DELAY = 250;
// Trigger proximity if distance is less than 5 cm.
private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
// Light sensor event rate in microseconds.
private static final int LIGHT_SENSOR_RATE = 1000000;
// Brightness animation ramp rate in brightness units per second.
private static final int BRIGHTNESS_RAMP_RATE_FAST = 200;
private static final int BRIGHTNESS_RAMP_RATE_SLOW = 50;
// Filter time constant in milliseconds for computing a moving
// average of light samples. Different constants are used
// to adapt to brighter or dimmer environments.
private static final long BRIGHTENING_LIGHT_TIME_CONSTANT = 2500; // 2.5 sec
private static final long DIMMING_LIGHT_TIME_CONSTANT = 10000; // 10 sec
private final Object mLock = new Object();
// Notifier for sending asynchronous notifications.
private final Notifier mNotifier;
// A suspend blocker.
private final SuspendBlocker mSuspendBlocker;
// Our handler.
private final DisplayControllerHandler mHandler;
// Asynchronous callbacks into the power manager service.
// Only invoked from the handler thread while no locks are held.
private final Callbacks mCallbacks;
private Handler mCallbackHandler;
// The lights service.
private final LightsService mLights;
// The sensor manager.
private final SensorManager mSensorManager;
// The proximity sensor, or null if not available or needed.
private Sensor mProximitySensor;
// The light sensor, or null if not available or needed.
private Sensor mLightSensor;
// The dim screen brightness.
private final int mScreenBrightnessDimConfig;
// Auto-brightness.
private boolean mUseSoftwareAutoBrightnessConfig;
private int[] mAutoBrightnessLevelsConfig;
private int[] mAutoBrightnessLcdBacklightValuesConfig;
// Amount of time to delay auto-brightness after screen on while waiting for
// the light sensor to warm-up in milliseconds.
// May be 0 if no warm-up is required.
private int mLightSensorWarmUpTimeConfig;
// The pending power request.
// Initially null until the first call to requestPowerState.
// Guarded by mLock.
private DisplayPowerRequest mPendingRequestLocked;
// True if a request has been made to wait for the proximity sensor to go negative.
// Guarded by mLock.
private boolean mPendingWaitForNegativeProximityLocked;
// True if the pending power request or wait for negative proximity flag
// has been changed since the last update occurred.
// Guarded by mLock.
private boolean mPendingRequestChangedLocked;
// Set to true when the important parts of the pending power request have been applied.
// The important parts are mainly the screen state. Brightness changes may occur
// concurrently.
// Guarded by mLock.
private boolean mDisplayReadyLocked;
// Set to true if a power state update is required.
// Guarded by mLock.
private boolean mPendingUpdatePowerStateLocked;
/* The following state must only be accessed by the handler thread. */
// The currently requested power state.
// The power controller will progressively update its internal state to match
// the requested power state. Initially null until the first update.
private DisplayPowerRequest mPowerRequest;
// The current power state.
// Must only be accessed on the handler thread.
private DisplayPowerState mPowerState;
// True if the device should wait for negative proximity sensor before
// waking up the screen. This is set to false as soon as a negative
// proximity sensor measurement is observed or when the device is forced to
// go to sleep by the user. While true, the screen remains off.
private boolean mWaitingForNegativeProximity;
// The actual proximity sensor threshold value.
private float mProximityThreshold;
// Set to true if the proximity sensor listener has been registered
// with the sensor manager.
private boolean mProximitySensorEnabled;
// The debounced proximity sensor state.
private int mProximity = PROXIMITY_UNKNOWN;
// The raw non-debounced proximity sensor state.
private int mPendingProximity = PROXIMITY_UNKNOWN;
private long mPendingProximityDebounceTime;
// True if the screen was turned off because of the proximity sensor.
// When the screen turns on again, we report user activity to the power manager.
private boolean mScreenOffBecauseOfProximity;
// Set to true if the light sensor is enabled.
private boolean mLightSensorEnabled;
// The time when the light sensor was enabled.
private long mLightSensorEnableTime;
// The currently accepted average light sensor value.
private float mLightMeasurement;
// True if the light sensor measurement is valid.
private boolean mLightMeasurementValid;
// The number of light sensor samples that have been collected since the
// last time a light sensor reading was accepted.
private int mRecentLightSamples;
// The moving average of recent light sensor values.
private float mRecentLightAverage;
// True if recent light samples are getting brighter than the previous
// stable light measurement.
private boolean mRecentLightBrightening;
// The time constant to use for filtering based on whether the
// light appears to be brightening or dimming.
private long mRecentLightTimeConstant;
// The most recent light sample.
private float mLastLightSample;
// The time of the most light recent sample.
private long mLastLightSampleTime;
// The upcoming debounce light sensor time.
// This is only valid when mLightMeasurementValue && mRecentLightSamples >= 1.
private long mPendingLightSensorDebounceTime;
// The screen brightness level that has been chosen by the auto-brightness
// algorithm. The actual brightness should ramp towards this value.
// We preserve this value even when we stop using the light sensor so
// that we can quickly revert to the previous auto-brightness level
// while the light sensor warms up.
// Use -1 if there is no current auto-brightness value available.
private int mScreenAutoBrightness = -1;
// True if the screen auto-brightness value is actually being used to
// set the display brightness.
private boolean mUsingScreenAutoBrightness;
// Animators.
private ObjectAnimator mElectronBeamOnAnimator;
private ObjectAnimator mElectronBeamOffAnimator;
private RampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator;
/**
* Creates the display power controller.
*/
public DisplayPowerController(Looper looper, Context context, Notifier notifier,
LightsService lights, SuspendBlocker suspendBlocker,
Callbacks callbacks, Handler callbackHandler) {
mHandler = new DisplayControllerHandler(looper);
mNotifier = notifier;
mSuspendBlocker = suspendBlocker;
mCallbacks = callbacks;
mCallbackHandler = callbackHandler;
mLights = lights;
mSensorManager = new SystemSensorManager(mHandler.getLooper());
final Resources resources = context.getResources();
mScreenBrightnessDimConfig = resources.getInteger(
com.android.internal.R.integer.config_screenBrightnessDim);
mUseSoftwareAutoBrightnessConfig = resources.getBoolean(
com.android.internal.R.bool.config_automatic_brightness_available);
if (mUseSoftwareAutoBrightnessConfig) {
mAutoBrightnessLevelsConfig = resources.getIntArray(
com.android.internal.R.array.config_autoBrightnessLevels);
mAutoBrightnessLcdBacklightValuesConfig = resources.getIntArray(
com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
if (mAutoBrightnessLcdBacklightValuesConfig.length
!= mAutoBrightnessLevelsConfig.length + 1) {
Slog.e(TAG, "Error in config.xml. config_autoBrightnessLcdBacklightValues "
+ "(size " + mAutoBrightnessLcdBacklightValuesConfig.length + ") "
+ "should have exactly one more entry than "
+ "config_autoBrightnessLevels (size "
+ mAutoBrightnessLevelsConfig.length + "). "
+ "Auto-brightness will be disabled.");
mUseSoftwareAutoBrightnessConfig = false;
}
mLightSensorWarmUpTimeConfig = resources.getInteger(
com.android.internal.R.integer.config_lightSensorWarmupTime);
}
if (!DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT) {
mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
if (mProximitySensor != null) {
mProximityThreshold = Math.min(mProximitySensor.getMaximumRange(),
TYPICAL_PROXIMITY_THRESHOLD);
}
}
if (mUseSoftwareAutoBrightnessConfig
&& !DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
}
}
/**
* Returns true if the proximity sensor screen-off function is available.
*/
public boolean isProximitySensorAvailable() {
return mProximitySensor != null;
}
/**
* Requests a new power state.
* The controller makes a copy of the provided object and then
* begins adjusting the power state to match what was requested.
*
* @param request The requested power state.
* @param waitForNegativeProximity If true, issues a request to wait for
* negative proximity before turning the screen back on, assuming the screen
* was turned off by the proximity sensor.
* @return True if display is ready, false if there are important changes that must
* be made asynchronously (such as turning the screen on), in which case the caller
* should grab a wake lock, watch for {@link Callbacks#onStateChanged()} then try
* the request again later until the state converges.
*/
public boolean requestPowerState(DisplayPowerRequest request,
boolean waitForNegativeProximity) {
if (DEBUG) {
Slog.d(TAG, "requestPowerState: "
+ request + ", waitForNegativeProximity=" + waitForNegativeProximity);
}
synchronized (mLock) {
boolean changed = false;
if (waitForNegativeProximity
&& !mPendingWaitForNegativeProximityLocked) {
mPendingWaitForNegativeProximityLocked = true;
changed = true;
}
if (mPendingRequestLocked == null) {
mPendingRequestLocked = new DisplayPowerRequest(request);
changed = true;
} else if (!mPendingRequestLocked.equals(request)) {
mPendingRequestLocked.copyFrom(request);
changed = true;
}
if (changed) {
mDisplayReadyLocked = false;
}
if (changed && !mPendingRequestChangedLocked) {
mPendingRequestChangedLocked = true;
sendUpdatePowerStateLocked();
}
return mDisplayReadyLocked;
}
}
private void sendUpdatePowerState() {
synchronized (mLock) {
sendUpdatePowerStateLocked();
}
}
private void sendUpdatePowerStateLocked() {
if (!mPendingUpdatePowerStateLocked) {
mPendingUpdatePowerStateLocked = true;
Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE);
msg.setAsynchronous(true);
mHandler.sendMessage(msg);
}
}
private void initialize() {
final Executor executor = AsyncTask.THREAD_POOL_EXECUTOR;
mPowerState = new DisplayPowerState(new ElectronBeam(),
new PhotonicModulator(executor,
mLights.getLight(LightsService.LIGHT_ID_BACKLIGHT),
mSuspendBlocker));
mElectronBeamOnAnimator = ObjectAnimator.ofFloat(
mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 0.0f, 1.0f);
mElectronBeamOnAnimator.setDuration(ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS);
mElectronBeamOnAnimator.addListener(mAnimatorListener);
mElectronBeamOffAnimator = ObjectAnimator.ofFloat(
mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 1.0f, 0.0f);
mElectronBeamOffAnimator.setDuration(ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS);
mElectronBeamOffAnimator.addListener(mAnimatorListener);
mScreenBrightnessRampAnimator = new RampAnimator<DisplayPowerState>(
mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS);
}
private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
sendUpdatePowerState();
}
@Override
public void onAnimationRepeat(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
};
private void updatePowerState() {
// Update the power state request.
final boolean mustNotify;
boolean mustInitialize = false;
synchronized (mLock) {
mPendingUpdatePowerStateLocked = false;
if (mPendingRequestLocked == null) {
return; // wait until first actual power request
}
if (mPowerRequest == null) {
mPowerRequest = new DisplayPowerRequest(mPendingRequestLocked);
mWaitingForNegativeProximity = mPendingWaitForNegativeProximityLocked;
mPendingRequestChangedLocked = false;
mustInitialize = true;
} else if (mPendingRequestChangedLocked) {
mPowerRequest.copyFrom(mPendingRequestLocked);
mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
mPendingRequestChangedLocked = false;
mDisplayReadyLocked = false;
}
mustNotify = !mDisplayReadyLocked;
}
// Initialize things the first time the power state is changed.
if (mustInitialize) {
initialize();
}
// Clear a request to wait for negative proximity if needed.
if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_OFF
|| mProximity == PROXIMITY_NEGATIVE
|| mProximitySensor == null) {
mWaitingForNegativeProximity = false;
}
// Turn on the proximity sensor if needed.
if (mProximitySensor != null) {
setProximitySensorEnabled(mPowerRequest.useProximitySensor
|| mWaitingForNegativeProximity);
if (mProximitySensorEnabled && mProximity == PROXIMITY_POSITIVE) {
mScreenOffBecauseOfProximity = true;
setScreenOn(false);
} else if (mScreenOffBecauseOfProximity) {
mScreenOffBecauseOfProximity = false;
sendOnProximityNegative();
}
}
// Turn on the light sensor if needed.
if (mLightSensor != null) {
setLightSensorEnabled(mPowerRequest.useAutoBrightness
&& wantScreenOn(mPowerRequest.screenState));
}
// Set the screen brightness.
if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
// Screen is dimmed. Overrides everything else.
animateScreenBrightness(mScreenBrightnessDimConfig, BRIGHTNESS_RAMP_RATE_FAST);
mUsingScreenAutoBrightness = false;
} else if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_BRIGHT) {
if (mScreenAutoBrightness >= 0 && mLightSensorEnabled) {
// Use current auto-brightness value.
animateScreenBrightness(
Math.max(mScreenAutoBrightness, mScreenBrightnessDimConfig),
mUsingScreenAutoBrightness ? BRIGHTNESS_RAMP_RATE_SLOW :
BRIGHTNESS_RAMP_RATE_FAST);
mUsingScreenAutoBrightness = true;
} else {
// Light sensor is disabled or not ready yet.
// Use the current brightness setting from the request, which is expected
// provide a nominal default value for the case where auto-brightness
// is not ready yet.
animateScreenBrightness(
Math.max(mPowerRequest.screenBrightness, mScreenBrightnessDimConfig),
BRIGHTNESS_RAMP_RATE_FAST);
mUsingScreenAutoBrightness = false;
}
} else {
// Screen is off. Don't bother changing the brightness.
mUsingScreenAutoBrightness = false;
}
// Animate the screen on or off.
if (!mScreenOffBecauseOfProximity) {
if (wantScreenOn(mPowerRequest.screenState)) {
// Want screen on.
// Wait for previous off animation to complete beforehand.
// It is relatively short but if we cancel it and switch to the
// on animation immediately then the results are pretty ugly.
if (!mElectronBeamOffAnimator.isStarted()) {
setScreenOn(true);
if (!mElectronBeamOnAnimator.isStarted()) {
if (mPowerState.getElectronBeamLevel() == 1.0f) {
mPowerState.dismissElectronBeam();
} else if (mPowerState.prepareElectronBeam(true)) {
mElectronBeamOnAnimator.start();
} else {
mElectronBeamOnAnimator.end();
}
}
}
} else {
// Want screen off.
// Wait for previous on animation to complete beforehand.
if (!mElectronBeamOnAnimator.isStarted()) {
if (!mElectronBeamOffAnimator.isStarted()) {
if (mPowerState.getElectronBeamLevel() == 0.0f) {
setScreenOn(false);
} else if (mPowerState.prepareElectronBeam(false)
&& mPowerState.isScreenOn()) {
mElectronBeamOffAnimator.start();
} else {
mElectronBeamOffAnimator.end();
}
}
}
}
}
// Report whether the display is ready for use.
// We mostly care about the screen state here, ignoring brightness changes
// which will be handled asynchronously.
if (mustNotify
&& !mElectronBeamOnAnimator.isStarted()
&& !mElectronBeamOffAnimator.isStarted()
&& mPowerState.waitUntilClean(mCleanListener)) {
synchronized (mLock) {
if (!mPendingRequestChangedLocked) {
mDisplayReadyLocked = true;
}
}
sendOnStateChanged();
}
}
private void setScreenOn(boolean on) {
if (!mPowerState.isScreenOn() == on) {
mPowerState.setScreenOn(on);
if (on) {
mNotifier.onScreenOn();
} else {
mNotifier.onScreenOff();
}
}
}
private void animateScreenBrightness(int target, int rate) {
if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
mNotifier.onScreenBrightness(target);
}
}
private final Runnable mCleanListener = new Runnable() {
@Override
public void run() {
sendUpdatePowerState();
}
};
private void setProximitySensorEnabled(boolean enable) {
if (enable) {
if (!mProximitySensorEnabled) {
mProximitySensorEnabled = true;
mPendingProximity = PROXIMITY_UNKNOWN;
mSensorManager.registerListener(mProximitySensorListener, mProximitySensor,
SensorManager.SENSOR_DELAY_NORMAL, mHandler);
}
} else {
if (mProximitySensorEnabled) {
mProximitySensorEnabled = false;
mProximity = PROXIMITY_UNKNOWN;
mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
mSensorManager.unregisterListener(mProximitySensorListener);
}
}
}
private void handleProximitySensorEvent(long time, boolean positive) {
if (mPendingProximity == PROXIMITY_NEGATIVE && !positive) {
return; // no change
}
if (mPendingProximity == PROXIMITY_POSITIVE && positive) {
return; // no change
}
// Only accept a proximity sensor reading if it remains
// stable for the entire debounce delay.
mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
mPendingProximity = positive ? PROXIMITY_POSITIVE : PROXIMITY_NEGATIVE;
mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_DEBOUNCE_DELAY;
debounceProximitySensor();
}
private void debounceProximitySensor() {
if (mPendingProximity != PROXIMITY_UNKNOWN) {
final long now = SystemClock.uptimeMillis();
if (mPendingProximityDebounceTime <= now) {
mProximity = mPendingProximity;
sendUpdatePowerState();
} else {
Message msg = mHandler.obtainMessage(MSG_PROXIMITY_SENSOR_DEBOUNCED);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, mPendingProximityDebounceTime);
}
}
}
private void setLightSensorEnabled(boolean enable) {
if (enable) {
if (!mLightSensorEnabled) {
mLightSensorEnabled = true;
mLightSensorEnableTime = SystemClock.uptimeMillis();
mSensorManager.registerListener(mLightSensorListener, mLightSensor,
LIGHT_SENSOR_RATE, mHandler);
}
} else {
if (mLightSensorEnabled) {
mLightSensorEnabled = false;
mLightMeasurementValid = false;
updateAutoBrightness(false);
mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
mSensorManager.unregisterListener(mLightSensorListener);
}
}
}
private void handleLightSensorEvent(long time, float lux) {
// Take the first few readings during the warm-up period and apply them
// immediately without debouncing.
if (!mLightMeasurementValid
|| (time - mLightSensorEnableTime) < mLightSensorWarmUpTimeConfig) {
mLightMeasurement = lux;
mLightMeasurementValid = true;
mRecentLightSamples = 0;
updateAutoBrightness(true);
}
// Update our moving average.
if (lux != mLightMeasurement && (mRecentLightSamples == 0
|| (lux < mLightMeasurement && mRecentLightBrightening)
|| (lux > mLightMeasurement && !mRecentLightBrightening))) {
// If the newest light sample doesn't seem to be going in the
// same general direction as recent samples, then start over.
setRecentLight(time, lux, lux > mLightMeasurement);
mPendingLightSensorDebounceTime = time + mRecentLightTimeConstant;
} else if (mRecentLightSamples >= 1) {
// Add the newest light sample to the moving average.
accumulateRecentLight(time, lux);
}
if (DEBUG) {
Slog.d(TAG, "handleLightSensorEvent: lux=" + lux
+ ", mLightMeasurementValid=" + mLightMeasurementValid
+ ", mLightMeasurement=" + mLightMeasurement
+ ", mRecentLightSamples=" + mRecentLightSamples
+ ", mRecentLightAverage=" + mRecentLightAverage
+ ", mRecentLightBrightening=" + mRecentLightBrightening
+ ", mRecentLightTimeConstant=" + mRecentLightTimeConstant
+ ", mPendingLightSensorDebounceTime="
+ TimeUtils.formatUptime(mPendingLightSensorDebounceTime));
}
// Debounce.
mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
debounceLightSensor();
}
private void setRecentLight(long time, float lux, boolean brightening) {
mRecentLightBrightening = brightening;
mRecentLightTimeConstant = brightening ?
BRIGHTENING_LIGHT_TIME_CONSTANT : DIMMING_LIGHT_TIME_CONSTANT;
mRecentLightSamples = 1;
mRecentLightAverage = lux;
mLastLightSample = lux;
mLastLightSampleTime = time;
}
private void accumulateRecentLight(long time, float lux) {
final long timeDelta = time - mLastLightSampleTime;
mRecentLightSamples += 1;
mRecentLightAverage += (lux - mRecentLightAverage) *
timeDelta / (mRecentLightTimeConstant + timeDelta);
mLastLightSample = lux;
mLastLightSampleTime = time;
}
private void debounceLightSensor() {
if (mLightMeasurementValid && mRecentLightSamples >= 1) {
final long now = SystemClock.uptimeMillis();
if (mPendingLightSensorDebounceTime <= now) {
accumulateRecentLight(now, mLastLightSample);
mLightMeasurement = mRecentLightAverage;
if (DEBUG) {
Slog.d(TAG, "debounceLightSensor: Accepted new measurement "
+ mLightMeasurement + " after "
+ (now - mPendingLightSensorDebounceTime
+ mRecentLightTimeConstant) + " ms based on "
+ mRecentLightSamples + " recent samples.");
}
updateAutoBrightness(true);
// Now that we have debounced the light sensor data, we have the
// option of either leaving the sensor in a debounced state or
// restarting the debounce cycle by setting mRecentLightSamples to 0.
//
// If we leave the sensor debounced, then new average light measurements
// may be accepted immediately as long as they are trending in the same
// direction as they were before. If the measurements start
// jittering or trending in the opposite direction then the debounce
// cycle will automatically be restarted. The benefit is that the
// auto-brightness control can be more responsive to changes over a
// broad range.
//
// For now, we choose to be more responsive and leave the following line
// commented out.
//
// mRecentLightSamples = 0;
} else {
Message msg = mHandler.obtainMessage(MSG_LIGHT_SENSOR_DEBOUNCED);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, mPendingLightSensorDebounceTime);
}
}
}
private void updateAutoBrightness(boolean sendUpdate) {
if (!mLightMeasurementValid) {
return;
}
final int newScreenAutoBrightness = mapLuxToBrightness(mLightMeasurement,
mAutoBrightnessLevelsConfig,
mAutoBrightnessLcdBacklightValuesConfig);
if (mScreenAutoBrightness != newScreenAutoBrightness) {
if (DEBUG) {
Slog.d(TAG, "updateAutoBrightness: mScreenAutoBrightness="
+ mScreenAutoBrightness);
}
mScreenAutoBrightness = newScreenAutoBrightness;
if (sendUpdate) {
sendUpdatePowerState();
}
}
}
/**
* Maps a light sensor measurement in lux to a brightness value given
* a table of lux breakpoint values and a table of brightnesses that
* is one element larger.
*/
private static int mapLuxToBrightness(float lux,
int[] fromLux, int[] toBrightness) {
// TODO implement interpolation and possibly range expansion
int level = 0;
final int count = fromLux.length;
while (level < count && lux >= fromLux[level]) {
level += 1;
}
return toBrightness[level];
}
private void sendOnStateChanged() {
mCallbackHandler.post(mOnStateChangedRunnable);
}
private final Runnable mOnStateChangedRunnable = new Runnable() {
@Override
public void run() {
mCallbacks.onStateChanged();
}
};
private void sendOnProximityNegative() {
mCallbackHandler.post(mOnProximityNegativeRunnable);
}
private final Runnable mOnProximityNegativeRunnable = new Runnable() {
@Override
public void run() {
mCallbacks.onProximityNegative();
}
};
public void dump(PrintWriter pw) {
synchronized (mLock) {
pw.println();
pw.println("Display Controller Locked State:");
pw.println(" mDisplayReadyLocked=" + mDisplayReadyLocked);
pw.println(" mPendingRequestLocked=" + mPendingRequestLocked);
pw.println(" mPendingRequestChangedLocked=" + mPendingRequestChangedLocked);
pw.println(" mPendingWaitForNegativeProximityLocked="
+ mPendingWaitForNegativeProximityLocked);
pw.println(" mPendingUpdatePowerStateLocked=" + mPendingUpdatePowerStateLocked);
}
pw.println();
pw.println("Display Controller Configuration:");
pw.println(" mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
pw.println(" mUseSoftwareAutoBrightnessConfig="
+ mUseSoftwareAutoBrightnessConfig);
pw.println(" mAutoBrightnessLevelsConfig="
+ Arrays.toString(mAutoBrightnessLevelsConfig));
pw.println(" mAutoBrightnessLcdBacklightValuesConfig="
+ Arrays.toString(mAutoBrightnessLcdBacklightValuesConfig));
pw.println(" mLightSensorWarmUpTimeConfig=" + mLightSensorWarmUpTimeConfig);
if (Looper.myLooper() == mHandler.getLooper()) {
dumpLocal(pw);
} else {
final StringWriter out = new StringWriter();
final CountDownLatch latch = new CountDownLatch(1);
Message msg = Message.obtain(mHandler, new Runnable() {
@Override
public void run() {
PrintWriter localpw = new PrintWriter(out);
try {
dumpLocal(localpw);
} finally {
localpw.flush();
latch.countDown();
}
}
});
msg.setAsynchronous(true);
mHandler.sendMessage(msg);
try {
latch.await();
pw.print(out.toString());
} catch (InterruptedException ex) {
pw.println();
pw.println("Failed to dump thread state due to interrupted exception!");
}
}
}
private void dumpLocal(PrintWriter pw) {
pw.println();
pw.println("Display Controller Thread State:");
pw.println(" mPowerRequest=" + mPowerRequest);
pw.println(" mWaitingForNegativeProximity=" + mWaitingForNegativeProximity);
pw.println(" mProximitySensor=" + mProximitySensor);
pw.println(" mProximitySensorEnabled=" + mProximitySensorEnabled);
pw.println(" mProximityThreshold=" + mProximityThreshold);
pw.println(" mProximity=" + proximityToString(mProximity));
pw.println(" mPendingProximity=" + proximityToString(mPendingProximity));
pw.println(" mPendingProximityDebounceTime="
+ TimeUtils.formatUptime(mPendingProximityDebounceTime));
pw.println(" mScreenOffBecauseOfProximity=" + mScreenOffBecauseOfProximity);
pw.println(" mLightSensor=" + mLightSensor);
pw.println(" mLightSensorEnabled=" + mLightSensorEnabled);
pw.println(" mLightSensorEnableTime="
+ TimeUtils.formatUptime(mLightSensorEnableTime));
pw.println(" mLightMeasurement=" + mLightMeasurement);
pw.println(" mLightMeasurementValid=" + mLightMeasurementValid);
pw.println(" mLastLightSample=" + mLastLightSample);
pw.println(" mLastLightSampleTime="
+ TimeUtils.formatUptime(mLastLightSampleTime));
pw.println(" mRecentLightSamples=" + mRecentLightSamples);
pw.println(" mRecentLightAverage=" + mRecentLightAverage);
pw.println(" mRecentLightBrightening=" + mRecentLightBrightening);
pw.println(" mRecentLightTimeConstant=" + mRecentLightTimeConstant);
pw.println(" mPendingLightSensorDebounceTime="
+ TimeUtils.formatUptime(mPendingLightSensorDebounceTime));
pw.println(" mScreenAutoBrightness=" + mScreenAutoBrightness);
pw.println(" mUsingScreenAutoBrightness=" + mUsingScreenAutoBrightness);
if (mElectronBeamOnAnimator != null) {
pw.println(" mElectronBeamOnAnimator.isStarted()=" +
mElectronBeamOnAnimator.isStarted());
}
if (mElectronBeamOffAnimator != null) {
pw.println(" mElectronBeamOffAnimator.isStarted()=" +
mElectronBeamOffAnimator.isStarted());
}
if (mPowerState != null) {
mPowerState.dump(pw);
}
}
private static String proximityToString(int state) {
switch (state) {
case PROXIMITY_UNKNOWN:
return "Unknown";
case PROXIMITY_NEGATIVE:
return "Negative";
case PROXIMITY_POSITIVE:
return "Positive";
default:
return Integer.toString(state);
}
}
private static boolean wantScreenOn(int state) {
switch (state) {
case DisplayPowerRequest.SCREEN_STATE_BRIGHT:
case DisplayPowerRequest.SCREEN_STATE_DIM:
return true;
}
return false;
}
/**
* Asynchronous callbacks from the power controller to the power manager service.
*/
public interface Callbacks {
void onStateChanged();
void onProximityNegative();
}
private final class DisplayControllerHandler extends Handler {
public DisplayControllerHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE_POWER_STATE:
updatePowerState();
break;
case MSG_PROXIMITY_SENSOR_DEBOUNCED:
debounceProximitySensor();
break;
case MSG_LIGHT_SENSOR_DEBOUNCED:
debounceLightSensor();
break;
}
}
}
private final SensorEventListener mProximitySensorListener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
if (mProximitySensorEnabled) {
final long time = SystemClock.uptimeMillis();
final float distance = event.values[0];
boolean positive = distance >= 0.0f && distance < mProximityThreshold;
handleProximitySensorEvent(time, positive);
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// Not used.
}
};
private final SensorEventListener mLightSensorListener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
if (mLightSensorEnabled) {
final long time = SystemClock.uptimeMillis();
final float lux = event.values[0];
handleLightSensorEvent(time, lux);
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// Not used.
}
};
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright (C) 2012 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.power;
import android.os.PowerManager;
/**
* Describes the requested power state of the display.
*
* This object is intended to describe the general characteristics of the
* power state, such as whether the screen should be on or off and the current
* brightness controls leaving the {@link DisplayPowerController} to manage the
* details of how the transitions between states should occur. The goal is for
* the {@link PowerManagerService} to focus on the global power state and not
* have to micro-manage screen off animations, auto-brightness and other effects.
*/
final class DisplayPowerRequest {
public static final int SCREEN_STATE_OFF = 0;
public static final int SCREEN_STATE_DIM = 1;
public static final int SCREEN_STATE_BRIGHT = 2;
// The requested minimum screen power state: off, dim or bright.
public int screenState;
// If true, the proximity sensor overrides the screen state when an object is
// nearby, turning it off temporarily until the object is moved away.
public boolean useProximitySensor;
// The desired screen brightness in the range 0 (minimum / off) to 255 (brightest).
// The display power controller may choose to clamp the brightness.
// When auto-brightness is enabled, this field should specify a nominal default
// value to use while waiting for the light sensor to report enough data.
public int screenBrightness;
// If true, enables automatic brightness control.
public boolean useAutoBrightness;
public DisplayPowerRequest() {
screenState = SCREEN_STATE_BRIGHT;
useProximitySensor = false;
screenBrightness = PowerManager.BRIGHTNESS_ON;
useAutoBrightness = false;
}
public DisplayPowerRequest(DisplayPowerRequest other) {
copyFrom(other);
}
public void copyFrom(DisplayPowerRequest other) {
screenState = other.screenState;
useProximitySensor = other.useProximitySensor;
screenBrightness = other.screenBrightness;
useAutoBrightness = other.useAutoBrightness;
}
@Override
public boolean equals(Object o) {
return o instanceof DisplayPowerRequest
&& equals((DisplayPowerRequest)o);
}
public boolean equals(DisplayPowerRequest other) {
return other != null
&& screenState == other.screenState
&& useProximitySensor == other.useProximitySensor
&& screenBrightness == other.screenBrightness
&& useAutoBrightness == other.useAutoBrightness;
}
@Override
public int hashCode() {
return 0; // don't care
}
@Override
public String toString() {
return "screenState=" + screenState
+ ", useProximitySensor=" + useProximitySensor
+ ", screenBrightness=" + screenBrightness
+ ", useAutoBrightness=" + useAutoBrightness;
}
}

View File

@@ -0,0 +1,269 @@
/*
* Copyright (C) 2012 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.power;
import android.os.Looper;
import android.os.PowerManager;
import android.util.FloatProperty;
import android.util.IntProperty;
import android.util.Slog;
import android.view.Choreographer;
import java.io.PrintWriter;
/**
* Represents the current display power state and realizes it.
*
* This component is similar in nature to a {@link View} except that it describes
* the properties of a display. When properties are changed, the component
* invalidates itself and posts a callback to the {@link Choreographer} to
* apply the changes. This mechanism enables the display power state to be
* animated smoothly by the animation framework.
*
* This component must only be created or accessed by the {@link Looper} thread
* that belongs to the {@link DisplayPowerController}.
*
* We don't need to worry about holding a suspend blocker here because the
* {@link DisplayPowerController} does that for us whenever there is a pending invalidate.
*/
final class DisplayPowerState {
private static final String TAG = "DisplayPowerState";
private static boolean DEBUG = false;
private static final int DIRTY_SCREEN_ON = 1 << 0;
private static final int DIRTY_ELECTRON_BEAM = 1 << 1;
private static final int DIRTY_BRIGHTNESS = 1 << 2;
private static final int DIRTY_ALL = 0xffffffff;
private final Choreographer mChoreographer;
private final ElectronBeam mElectronBeam;
private final PhotonicModulator mScreenBrightnessModulator;
private int mDirty;
private boolean mScreenOn;
private float mElectronBeamLevel;
private int mScreenBrightness;
private Runnable mCleanListener;
public DisplayPowerState(ElectronBeam electronBean,
PhotonicModulator screenBrightnessModulator) {
mChoreographer = Choreographer.getInstance();
mElectronBeam = electronBean;
mScreenBrightnessModulator = screenBrightnessModulator;
mScreenOn = true;
mElectronBeamLevel = 1.0f;
mScreenBrightness = PowerManager.BRIGHTNESS_ON;
invalidate(DIRTY_ALL);
}
public static final FloatProperty<DisplayPowerState> ELECTRON_BEAM_LEVEL =
new FloatProperty<DisplayPowerState>("electronBeamLevel") {
@Override
public void setValue(DisplayPowerState object, float value) {
object.setElectronBeamLevel(value);
}
@Override
public Float get(DisplayPowerState object) {
return object.getElectronBeamLevel();
}
};
public static final IntProperty<DisplayPowerState> SCREEN_BRIGHTNESS =
new IntProperty<DisplayPowerState>("screenBrightness") {
@Override
public void setValue(DisplayPowerState object, int value) {
object.setScreenBrightness(value);
}
@Override
public Integer get(DisplayPowerState object) {
return object.getScreenBrightness();
}
};
/**
* Sets whether the screen is on or off.
*/
public void setScreenOn(boolean on) {
if (mScreenOn != on) {
if (DEBUG) {
Slog.d(TAG, "setScreenOn: on=" + on);
}
mScreenOn = on;
invalidate(DIRTY_SCREEN_ON);
}
}
/**
* Returns true if the screen is on.
*/
public boolean isScreenOn() {
return mScreenOn;
}
/**
* Prepares the electron beam to turn on or off.
* This method should be called before starting an animation because it
* can take a fair amount of time to prepare the electron beam surface.
*
* @param warmUp True if the electron beam should start warming up.
* @return True if the electron beam was prepared.
*/
public boolean prepareElectronBeam(boolean warmUp) {
boolean success = mElectronBeam.prepare(warmUp);
invalidate(DIRTY_ELECTRON_BEAM);
return success;
}
/**
* Dismisses the electron beam surface.
*/
public void dismissElectronBeam() {
mElectronBeam.dismiss();
}
/**
* Sets the level of the electron beam steering current.
*
* The display is blanked when the level is 0.0. In normal use, the electron
* beam should have a value of 1.0. The electron beam is unstable in between
* these states and the picture quality may be compromised. For best effect,
* the electron beam should be warmed up or cooled off slowly.
*
* Warning: Electron beam emits harmful radiation. Avoid direct exposure to
* skin or eyes.
*
* @param level The level, ranges from 0.0 (full off) to 1.0 (full on).
*/
public void setElectronBeamLevel(float level) {
if (mElectronBeamLevel != level) {
if (DEBUG) {
Slog.d(TAG, "setElectronBeamLevel: level=" + level);
}
mElectronBeamLevel = level;
invalidate(DIRTY_ELECTRON_BEAM);
}
}
/**
* Gets the level of the electron beam steering current.
*/
public float getElectronBeamLevel() {
return mElectronBeamLevel;
}
/**
* Sets the display brightness.
*
* @param brightness The brightness, ranges from 0 (minimum / off) to 255 (brightest).
*/
public void setScreenBrightness(int brightness) {
if (mScreenBrightness != brightness) {
if (DEBUG) {
Slog.d(TAG, "setScreenBrightness: brightness=" + brightness);
}
mScreenBrightness = brightness;
invalidate(DIRTY_BRIGHTNESS);
}
}
/**
* Gets the screen brightness.
*/
public int getScreenBrightness() {
return mScreenBrightness;
}
/**
* Returns true if no properties have been invalidated.
* Otherwise, returns false and promises to invoke the specified listener
* when the properties have all been applied.
* The listener always overrides any previously set listener.
*/
public boolean waitUntilClean(Runnable listener) {
if (mDirty != 0) {
mCleanListener = listener;
return false;
} else {
mCleanListener = null;
return true;
}
}
public void dump(PrintWriter pw) {
pw.println();
pw.println("Display Power State:");
pw.println(" mDirty=" + Integer.toHexString(mDirty));
pw.println(" mScreenOn=" + mScreenOn);
pw.println(" mScreenBrightness=" + mScreenBrightness);
pw.println(" mElectronBeamLevel=" + mElectronBeamLevel);
mElectronBeam.dump(pw);
}
private void invalidate(int dirty) {
if (mDirty == 0) {
mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL,
mTraversalRunnable, null);
}
mDirty |= dirty;
}
private void apply() {
if (mDirty != 0) {
if ((mDirty & DIRTY_SCREEN_ON) != 0 && !mScreenOn) {
PowerManagerService.nativeSetScreenState(false);
}
if ((mDirty & DIRTY_ELECTRON_BEAM) != 0) {
mElectronBeam.draw(mElectronBeamLevel);
}
if ((mDirty & DIRTY_BRIGHTNESS) != 0) {
mScreenBrightnessModulator.setBrightness(mScreenBrightness);
}
if ((mDirty & DIRTY_SCREEN_ON) != 0 && mScreenOn) {
PowerManagerService.nativeSetScreenState(true);
}
mDirty = 0;
if (mCleanListener != null) {
mCleanListener.run();
}
}
}
private final Runnable mTraversalRunnable = new Runnable() {
@Override
public void run() {
if (mDirty != 0) {
apply();
}
}
};
}

View File

@@ -0,0 +1,652 @@
/*
* Copyright (C) 2012 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.power;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.opengl.EGL14;
import android.opengl.EGLConfig;
import android.opengl.EGLContext;
import android.opengl.EGLDisplay;
import android.opengl.EGLSurface;
import android.opengl.GLES10;
import android.opengl.GLUtils;
import android.os.Looper;
import android.os.Process;
import android.util.FloatMath;
import android.util.Slog;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.Surface;
import android.view.SurfaceSession;
import android.view.WindowManagerImpl;
import java.io.PrintWriter;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
/**
* Bzzzoooop! *crackle*
*
* Animates a screen transition from on to off or off to on by applying
* some GL transformations to a screenshot.
*
* This component must only be created or accessed by the {@link Looper} thread
* that belongs to the {@link DisplayPowerController}.
*/
final class ElectronBeam {
private static final String TAG = "ElectronBeam";
private static final boolean DEBUG = false;
// The layer for the electron beam surface.
// This is currently hardcoded to be one layer above the boot animation.
private static final int ELECTRON_BEAM_LAYER = 0x40000001;
// The relative proportion of the animation to spend performing
// the horizontal stretch effect. The remainder is spent performing
// the vertical stretch effect.
private static final float HSTRETCH_DURATION = 0.3f;
private static final float VSTRETCH_DURATION = 1.0f - HSTRETCH_DURATION;
// Set to true when the animation context has been fully prepared.
private boolean mPrepared;
private boolean mWarmUp;
private final DisplayInfo mDisplayInfo = new DisplayInfo();
private int mDisplayLayerStack; // layer stack associated with primary display
private int mDisplayRotation;
private int mDisplayWidth; // real width, not rotated
private int mDisplayHeight; // real height, not rotated
private SurfaceSession mSurfaceSession;
private Surface mSurface;
private EGLDisplay mEglDisplay;
private EGLConfig mEglConfig;
private EGLContext mEglContext;
private EGLSurface mEglSurface;
private boolean mSurfaceVisible;
// Texture names. We only use one texture, which contains the screenshot.
private final int[] mTexNames = new int[1];
private boolean mTexNamesGenerated;
// Vertex and corresponding texture coordinates.
// We have 4 2D vertices, so 8 elements. The vertices form a quad.
private final FloatBuffer mVertexBuffer = createNativeFloatBuffer(8);
private final FloatBuffer mTexCoordBuffer = createNativeFloatBuffer(8);
public ElectronBeam() {
}
/**
* Warms up the electron beam in preparation for turning on or off.
* This method prepares a GL context, and captures a screen shot.
*
* @param warmUp True if the electron beam is about to be turned on, false if
* it is about to be turned off.
* @return True if the electron beam is ready, false if it is uncontrollable.
*/
public boolean prepare(boolean warmUp) {
if (DEBUG) {
Slog.d(TAG, "prepare: warmUp=" + warmUp);
}
mWarmUp = warmUp;
// Get the display size and adjust it for rotation.
Display display = WindowManagerImpl.getDefault().getDefaultDisplay();
display.getDisplayInfo(mDisplayInfo);
mDisplayLayerStack = display.getDisplayId();
mDisplayRotation = mDisplayInfo.rotation;
if (mDisplayRotation == Surface.ROTATION_90
|| mDisplayRotation == Surface.ROTATION_270) {
mDisplayWidth = mDisplayInfo.logicalHeight;
mDisplayHeight = mDisplayInfo.logicalWidth;
} else {
mDisplayWidth = mDisplayInfo.logicalWidth;
mDisplayHeight = mDisplayInfo.logicalHeight;
}
// Prepare the surface for drawing.
if (!createEglContext()
|| !createEglSurface()
|| !captureScreenshotTextureAndSetViewport()) {
dismiss();
return false;
}
mPrepared = true;
return true;
}
/**
* Dismisses the electron beam animation surface and cleans up.
*
* To prevent stray photons from leaking out after the electron beam has been
* turned off, it is a good idea to defer dismissing the animation until the
* electron beam has been turned back on fully.
*/
public void dismiss() {
if (DEBUG) {
Slog.d(TAG, "dismiss");
}
destroyScreenshotTexture();
destroyEglSurface();
mPrepared = false;
}
/**
* Draws an animation frame showing the electron beam activated at the
* specified level.
*
* @param level The electron beam level.
* @return True if successful.
*/
public boolean draw(float level) {
if (DEBUG) {
Slog.d(TAG, "drawFrame: level=" + level);
}
if (!attachEglContext()) {
return false;
}
try {
// Clear frame to solid black.
GLES10.glClearColor(0f, 0f, 0f, 1f);
GLES10.glClear(GLES10.GL_COLOR_BUFFER_BIT);
// Draw the frame.
if (level < HSTRETCH_DURATION) {
drawHStretch(1.0f - (level / HSTRETCH_DURATION));
} else {
drawVStretch(1.0f - ((level - HSTRETCH_DURATION) / VSTRETCH_DURATION));
}
if (checkGlErrors("drawFrame")) {
return false;
}
EGL14.eglSwapBuffers(mEglDisplay, mEglSurface);
} finally {
detachEglContext();
}
return showEglSurface();
}
/**
* Draws a frame where the content of the electron beam is collapsing inwards upon
* itself vertically with red / green / blue channels dispersing and eventually
* merging down to a single horizontal line.
*
* @param stretch The stretch factor. 0.0 is no collapse, 1.0 is full collapse.
*/
private void drawVStretch(float stretch) {
// compute interpolation scale factors for each color channel
final float ar = scurve(stretch, 7.5f);
final float ag = scurve(stretch, 8.0f);
final float ab = scurve(stretch, 8.5f);
if (DEBUG) {
Slog.d(TAG, "drawVStretch: stretch=" + stretch
+ ", ar=" + ar + ", ag=" + ag + ", ab=" + ab);
}
// set blending
GLES10.glBlendFunc(GLES10.GL_ONE, GLES10.GL_ONE);
GLES10.glEnable(GLES10.GL_BLEND);
// bind vertex buffer
GLES10.glVertexPointer(2, GLES10.GL_FLOAT, 0, mVertexBuffer);
GLES10.glEnableClientState(GLES10.GL_VERTEX_ARRAY);
// bind texture and set blending for drawing planes
GLES10.glBindTexture(GLES10.GL_TEXTURE_2D, mTexNames[0]);
GLES10.glTexEnvx(GLES10.GL_TEXTURE_ENV, GLES10.GL_TEXTURE_ENV_MODE,
mWarmUp ? GLES10.GL_MODULATE : GLES10.GL_REPLACE);
GLES10.glTexParameterx(GLES10.GL_TEXTURE_2D,
GLES10.GL_TEXTURE_MAG_FILTER, GLES10.GL_LINEAR);
GLES10.glTexParameterx(GLES10.GL_TEXTURE_2D,
GLES10.GL_TEXTURE_MIN_FILTER, GLES10.GL_LINEAR);
GLES10.glTexParameterx(GLES10.GL_TEXTURE_2D,
GLES10.GL_TEXTURE_WRAP_S, GLES10.GL_CLAMP_TO_EDGE);
GLES10.glTexParameterx(GLES10.GL_TEXTURE_2D,
GLES10.GL_TEXTURE_WRAP_T, GLES10.GL_CLAMP_TO_EDGE);
GLES10.glEnable(GLES10.GL_TEXTURE_2D);
GLES10.glTexCoordPointer(2, GLES10.GL_FLOAT, 0, mTexCoordBuffer);
GLES10.glEnableClientState(GLES10.GL_TEXTURE_COORD_ARRAY);
// draw the red plane
setVStretchQuad(mVertexBuffer, mDisplayWidth, mDisplayHeight, ar);
GLES10.glColorMask(true, false, false, true);
GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
// draw the green plane
setVStretchQuad(mVertexBuffer, mDisplayWidth, mDisplayHeight, ag);
GLES10.glColorMask(false, true, false, true);
GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
// draw the blue plane
setVStretchQuad(mVertexBuffer, mDisplayWidth, mDisplayHeight, ab);
GLES10.glColorMask(false, false, true, true);
GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
// clean up after drawing planes
GLES10.glDisable(GLES10.GL_TEXTURE_2D);
GLES10.glDisableClientState(GLES10.GL_TEXTURE_COORD_ARRAY);
GLES10.glColorMask(true, true, true, true);
// draw the white highlight (we use the last vertices)
if (!mWarmUp) {
GLES10.glColor4f(ag, ag, ag, 1.0f);
GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
}
// clean up
GLES10.glDisableClientState(GLES10.GL_VERTEX_ARRAY);
GLES10.glDisable(GLES10.GL_BLEND);
}
/**
* Draws a frame where the electron beam has been stretched out into
* a thin white horizontal line that fades as it expands outwards.
*
* @param stretch The stretch factor. 0.0 is no stretch / no fade,
* 1.0 is maximum stretch / maximum fade.
*/
private void drawHStretch(float stretch) {
// compute interpolation scale factor
final float ag = scurve(stretch, 8.0f);
if (DEBUG) {
Slog.d(TAG, "drawHStretch: stretch=" + stretch + ", ag=" + ag);
}
if (stretch < 1.0f) {
// bind vertex buffer
GLES10.glVertexPointer(2, GLES10.GL_FLOAT, 0, mVertexBuffer);
GLES10.glEnableClientState(GLES10.GL_VERTEX_ARRAY);
// draw narrow fading white line
setHStretchQuad(mVertexBuffer, mDisplayWidth, mDisplayHeight, ag);
GLES10.glColor4f(1.0f - ag, 1.0f - ag, 1.0f - ag, 1.0f);
GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
// clean up
GLES10.glDisableClientState(GLES10.GL_VERTEX_ARRAY);
}
}
private static void setVStretchQuad(FloatBuffer vtx, float dw, float dh, float a) {
final float w = dw + (dw * a);
final float h = dh - (dh * a);
final float x = (dw - w) * 0.5f;
final float y = (dh - h) * 0.5f;
setQuad(vtx, x, y, w, h);
}
private static void setHStretchQuad(FloatBuffer vtx, float dw, float dh, float a) {
final float w = dw + (dw * a);
final float h = 1.0f;
final float x = (dw - w) * 0.5f;
final float y = (dh - h) * 0.5f;
setQuad(vtx, x, y, w, h);
}
private static void setQuad(FloatBuffer vtx, float x, float y, float w, float h) {
if (DEBUG) {
Slog.d(TAG, "setQuad: x=" + x + ", y=" + y + ", w=" + w + ", h=" + h);
}
vtx.put(0, x);
vtx.put(1, y);
vtx.put(2, x);
vtx.put(3, y + h);
vtx.put(4, x + w);
vtx.put(5, y + h);
vtx.put(6, x + w);
vtx.put(7, y);
}
private boolean captureScreenshotTextureAndSetViewport() {
// TODO: Use a SurfaceTexture to avoid the extra texture upload.
Bitmap bitmap = Surface.screenshot(mDisplayWidth, mDisplayHeight,
0, ELECTRON_BEAM_LAYER - 1);
if (bitmap == null) {
Slog.e(TAG, "Could not take a screenshot!");
return false;
}
try {
if (!attachEglContext()) {
return false;
}
try {
if (!mTexNamesGenerated) {
GLES10.glGenTextures(1, mTexNames, 0);
if (checkGlErrors("glGenTextures")) {
return false;
}
mTexNamesGenerated = true;
}
GLES10.glBindTexture(GLES10.GL_TEXTURE_2D, mTexNames[0]);
if (checkGlErrors("glBindTexture")) {
return false;
}
float u = 1.0f;
float v = 1.0f;
GLUtils.texImage2D(GLES10.GL_TEXTURE_2D, 0, bitmap, 0);
if (checkGlErrors("glTexImage2D, first try", false)) {
// Try a power of two size texture instead.
int tw = nextPowerOfTwo(mDisplayWidth);
int th = nextPowerOfTwo(mDisplayHeight);
int format = GLUtils.getInternalFormat(bitmap);
GLES10.glTexImage2D(GLES10.GL_TEXTURE_2D, 0,
format, tw, th, 0,
format, GLES10.GL_UNSIGNED_BYTE, null);
if (checkGlErrors("glTexImage2D, second try")) {
return false;
}
GLUtils.texSubImage2D(GLES10.GL_TEXTURE_2D, 0, 0, 0, bitmap);
if (checkGlErrors("glTexSubImage2D")) {
return false;
}
u = (float)mDisplayWidth / tw;
v = (float)mDisplayHeight / th;
}
// Set up texture coordinates for a quad.
// We might need to change this if the texture ends up being
// a different size from the display for some reason.
mTexCoordBuffer.put(0, 0f);
mTexCoordBuffer.put(1, v);
mTexCoordBuffer.put(2, 0f);
mTexCoordBuffer.put(3, 0f);
mTexCoordBuffer.put(4, u);
mTexCoordBuffer.put(5, 0f);
mTexCoordBuffer.put(6, u);
mTexCoordBuffer.put(7, v);
// Set up our viewport.
GLES10.glViewport(0, 0, mDisplayWidth, mDisplayHeight);
GLES10.glMatrixMode(GLES10.GL_PROJECTION);
GLES10.glLoadIdentity();
GLES10.glOrthof(0, mDisplayWidth, 0, mDisplayHeight, 0, 1);
GLES10.glMatrixMode(GLES10.GL_MODELVIEW);
GLES10.glLoadIdentity();
GLES10.glMatrixMode(GLES10.GL_TEXTURE);
GLES10.glLoadIdentity();
} finally {
detachEglContext();
}
} finally {
bitmap.recycle();
}
return true;
}
private void destroyScreenshotTexture() {
if (mTexNamesGenerated) {
mTexNamesGenerated = false;
if (attachEglContext()) {
try {
GLES10.glDeleteTextures(1, mTexNames, 0);
checkGlErrors("glDeleteTextures");
} finally {
detachEglContext();
}
}
}
}
private boolean createEglContext() {
if (mEglDisplay == null) {
mEglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
if (mEglDisplay == EGL14.EGL_NO_DISPLAY) {
logEglError("eglGetDisplay");
return false;
}
int[] version = new int[2];
if (!EGL14.eglInitialize(mEglDisplay, version, 0, version, 1)) {
mEglDisplay = null;
logEglError("eglInitialize");
return false;
}
}
if (mEglConfig == null) {
int[] eglConfigAttribList = new int[] {
EGL14.EGL_RED_SIZE, 8,
EGL14.EGL_GREEN_SIZE, 8,
EGL14.EGL_BLUE_SIZE, 8,
EGL14.EGL_ALPHA_SIZE, 8,
EGL14.EGL_NONE
};
int[] numEglConfigs = new int[1];
EGLConfig[] eglConfigs = new EGLConfig[1];
if (!EGL14.eglChooseConfig(mEglDisplay, eglConfigAttribList, 0,
eglConfigs, 0, eglConfigs.length, numEglConfigs, 0)) {
logEglError("eglChooseConfig");
return false;
}
mEglConfig = eglConfigs[0];
}
if (mEglContext == null) {
int[] eglContextAttribList = new int[] {
EGL14.EGL_NONE
};
mEglContext = EGL14.eglCreateContext(mEglDisplay, mEglConfig,
EGL14.EGL_NO_CONTEXT, eglContextAttribList, 0);
if (mEglContext == null) {
logEglError("eglCreateContext");
return false;
}
}
return true;
}
/* not used because it is too expensive to create / destroy contexts all of the time
private void destroyEglContext() {
if (mEglContext != null) {
if (!EGL14.eglDestroyContext(mEglDisplay, mEglContext)) {
logEglError("eglDestroyContext");
}
mEglContext = null;
}
}*/
private boolean createEglSurface() {
if (mSurfaceSession == null) {
mSurfaceSession = new SurfaceSession();
}
Surface.openTransaction();
try {
if (mSurface == null) {
try {
mSurface = new Surface(mSurfaceSession, Process.myPid(),
"ElectronBeam", mDisplayLayerStack, mDisplayWidth, mDisplayHeight,
PixelFormat.OPAQUE, Surface.OPAQUE | Surface.HIDDEN);
} catch (Surface.OutOfResourcesException ex) {
Slog.e(TAG, "Unable to create surface.", ex);
return false;
}
}
mSurface.setSize(mDisplayWidth, mDisplayHeight);
switch (mDisplayRotation) {
case Surface.ROTATION_0:
mSurface.setPosition(0, 0);
mSurface.setMatrix(1, 0, 0, 1);
break;
case Surface.ROTATION_90:
mSurface.setPosition(0, mDisplayWidth);
mSurface.setMatrix(0, -1, 1, 0);
break;
case Surface.ROTATION_180:
mSurface.setPosition(mDisplayWidth, mDisplayHeight);
mSurface.setMatrix(-1, 0, 0, -1);
break;
case Surface.ROTATION_270:
mSurface.setPosition(mDisplayHeight, 0);
mSurface.setMatrix(0, 1, -1, 0);
break;
}
} finally {
Surface.closeTransaction();
}
if (mEglSurface == null) {
int[] eglSurfaceAttribList = new int[] {
EGL14.EGL_NONE
};
mEglSurface = EGL14.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface,
eglSurfaceAttribList, 0);
if (mEglSurface == null) {
logEglError("eglCreateWindowSurface");
return false;
}
}
return true;
}
private void destroyEglSurface() {
if (mEglSurface != null) {
if (!EGL14.eglDestroySurface(mEglDisplay, mEglSurface)) {
logEglError("eglDestroySurface");
}
mEglSurface = null;
}
if (mSurface != null) {
Surface.openTransaction();
try {
mSurface.destroy();
} finally {
Surface.closeTransaction();
}
mSurface = null;
mSurfaceVisible = false;
}
}
private boolean showEglSurface() {
if (!mSurfaceVisible) {
Surface.openTransaction();
try {
mSurface.setLayer(ELECTRON_BEAM_LAYER);
mSurface.show();
} finally {
Surface.closeTransaction();
}
mSurfaceVisible = true;
}
return true;
}
private boolean attachEglContext() {
if (mEglSurface == null) {
return false;
}
if (!EGL14.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
logEglError("eglMakeCurrent");
return false;
}
return true;
}
private void detachEglContext() {
if (mEglDisplay != null) {
EGL14.eglMakeCurrent(mEglDisplay,
EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);
}
}
/**
* Interpolates a value in the range 0 .. 1 along a sigmoid curve
* yielding a result in the range 0 .. 1 scaled such that:
* scurve(0) == 0, scurve(0.5) == 0.5, scurve(1) == 1.
*/
private static float scurve(float value, float s) {
// A basic sigmoid has the form y = 1.0f / FloatMap.exp(-x * s).
// Here we take the input datum and shift it by 0.5 so that the
// domain spans the range -0.5 .. 0.5 instead of 0 .. 1.
final float x = value - 0.5f;
// Next apply the sigmoid function to the scaled value
// which produces a value in the range 0 .. 1 so we subtract
// 0.5 to get a value in the range -0.5 .. 0.5 instead.
final float y = sigmoid(x, s) - 0.5f;
// To obtain the desired boundary conditions we need to scale
// the result so that it fills a range of -1 .. 1.
final float v = sigmoid(0.5f, s) - 0.5f;
// And finally remap the value back to a range of 0 .. 1.
return y / v * 0.5f + 0.5f;
}
private static float sigmoid(float x, float s) {
return 1.0f / (1.0f + FloatMath.exp(-x * s));
}
private static int nextPowerOfTwo(int value) {
return 1 << (32 - Integer.numberOfLeadingZeros(value));
}
private static FloatBuffer createNativeFloatBuffer(int size) {
ByteBuffer bb = ByteBuffer.allocateDirect(size * 4);
bb.order(ByteOrder.nativeOrder());
return bb.asFloatBuffer();
}
private static void logEglError(String func) {
Slog.e(TAG, func + " failed: error " + EGL14.eglGetError(), new Throwable());
}
private static boolean checkGlErrors(String func) {
return checkGlErrors(func, true);
}
private static boolean checkGlErrors(String func, boolean log) {
boolean hadError = false;
int error;
while ((error = GLES10.glGetError()) != GLES10.GL_NO_ERROR) {
if (log) {
Slog.e(TAG, func + " failed: error " + error, new Throwable());
}
hadError = true;
}
return hadError;
}
public void dump(PrintWriter pw) {
pw.println();
pw.println("Electron Beam State:");
pw.println(" mPrepared=" + mPrepared);
pw.println(" mWarmUp=" + mWarmUp);
pw.println(" mDisplayLayerStack=" + mDisplayLayerStack);
pw.println(" mDisplayRotation=" + mDisplayRotation);
pw.println(" mDisplayWidth=" + mDisplayWidth);
pw.println(" mDisplayHeight=" + mDisplayHeight);
pw.println(" mSurfaceVisible=" + mSurfaceVisible);
}
}

View File

@@ -0,0 +1,458 @@
/*
* Copyright (C) 2012 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.power;
import com.android.internal.app.IBatteryStats;
import com.android.server.EventLogTags;
import android.app.ActivityManagerNative;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.BatteryStats;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.WorkSource;
import android.util.EventLog;
import android.util.Slog;
import android.view.WindowManagerPolicy;
import android.view.WindowManagerPolicy.ScreenOnListener;
/**
* Sends broadcasts about important power state changes.
*
* This methods of this class may be called by the power manager service while
* its lock is being held. Internally it takes care of sending broadcasts to
* notify other components of the system or applications asynchronously.
*
* The notifier is designed to collapse unnecessary broadcasts when it is not
* possible for the system to have observed an intermediate state.
*
* For example, if the device wakes up, goes to sleep and wakes up again immediately
* before the go to sleep broadcast has been sent, then no broadcast will be
* sent about the system going to sleep and waking up.
*/
final class Notifier {
private static final String TAG = "PowerManagerNotifier";
private static final boolean DEBUG = false;
private static final int POWER_STATE_UNKNOWN = 0;
private static final int POWER_STATE_AWAKE = 1;
private static final int POWER_STATE_ASLEEP = 2;
private static final int MSG_USER_ACTIVITY = 1;
private static final int MSG_BROADCAST = 2;
private final Object mLock = new Object();
private final Context mContext;
private final IBatteryStats mBatteryStats;
private final SuspendBlocker mSuspendBlocker;
private final WindowManagerPolicy mPolicy;
private final ScreenOnListener mScreenOnListener;
private final NotifierHandler mHandler;
private final Intent mScreenOnIntent;
private final Intent mScreenOffIntent;
// The current power state.
private int mActualPowerState;
private int mLastGoToSleepReason;
// The currently broadcasted power state. This reflects what other parts of the
// system have observed.
private int mBroadcastedPowerState;
private boolean mBroadcastInProgress;
private long mBroadcastStartTime;
// True if a user activity message should be sent.
private boolean mUserActivityPending;
public Notifier(Looper looper, Context context, IBatteryStats batteryStats,
SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
ScreenOnListener screenOnListener) {
mContext = context;
mBatteryStats = batteryStats;
mSuspendBlocker = suspendBlocker;
mPolicy = policy;
mScreenOnListener = screenOnListener;
mHandler = new NotifierHandler(looper);
mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
mScreenOnIntent.addFlags(
Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF);
mScreenOffIntent.addFlags(
Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
}
/**
* Called when a wake lock is acquired.
*/
public void onWakeLockAcquired(int flags, String tag, int ownerUid, int ownerPid,
WorkSource workSource) {
if (DEBUG) {
Slog.d(TAG, "onWakeLockAcquired: flags=" + flags + ", tag=\"" + tag
+ "\", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
+ ", workSource=" + workSource);
}
if (!isWakeLockAlreadyReportedToBatteryStats(tag, ownerUid)) {
try {
final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
if (workSource != null) {
mBatteryStats.noteStartWakelockFromSource(
workSource, ownerPid, tag, monitorType);
} else {
mBatteryStats.noteStartWakelock(
ownerUid, ownerPid, tag, monitorType);
}
} catch (RemoteException ex) {
// Ignore
}
}
}
/**
* Called when a wake lock is released.
*/
public void onWakeLockReleased(int flags, String tag, int ownerUid, int ownerPid,
WorkSource workSource) {
if (DEBUG) {
Slog.d(TAG, "onWakeLockReleased: flags=" + flags + ", tag=\"" + tag
+ "\", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
+ ", workSource=" + workSource);
}
if (!isWakeLockAlreadyReportedToBatteryStats(tag, ownerUid)) {
try {
final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
if (workSource != null) {
mBatteryStats.noteStopWakelockFromSource(
workSource, ownerPid, tag, monitorType);
} else {
mBatteryStats.noteStopWakelock(
ownerUid, ownerPid, tag, monitorType);
}
} catch (RemoteException ex) {
// Ignore
}
}
}
private static boolean isWakeLockAlreadyReportedToBatteryStats(String tag, int uid) {
// The window manager already takes care of reporting battery stats associated
// with the use of the KEEP_SCREEN_ON_FLAG.
// TODO: Use a WorkSource to handle this situation instead of hardcoding it here.
return uid == Process.SYSTEM_UID
&& tag.equals(PowerManager.KEEP_SCREEN_ON_FLAG_TAG);
}
private static int getBatteryStatsWakeLockMonitorType(int flags) {
switch (flags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
case PowerManager.PARTIAL_WAKE_LOCK:
case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
return BatteryStats.WAKE_TYPE_PARTIAL;
default:
return BatteryStats.WAKE_TYPE_FULL;
}
}
/**
* Called when the screen is turned on.
*/
public void onScreenOn() {
if (DEBUG) {
Slog.d(TAG, "onScreenOn");
}
try {
mBatteryStats.noteScreenOn();
} catch (RemoteException ex) {
// Ignore
}
}
/**
* Called when the screen is turned off.
*/
public void onScreenOff() {
if (DEBUG) {
Slog.d(TAG, "onScreenOff");
}
try {
mBatteryStats.noteScreenOff();
} catch (RemoteException ex) {
// Ignore
}
}
/**
* Called when the screen changes brightness.
*/
public void onScreenBrightness(int brightness) {
if (DEBUG) {
Slog.d(TAG, "onScreenBrightness: brightness=" + brightness);
}
try {
mBatteryStats.noteScreenBrightness(brightness);
} catch (RemoteException ex) {
// Ignore
}
}
/**
* Called when the device is waking up from sleep and the
* display is about to be turned on.
*/
public void onWakeUpStarted() {
if (DEBUG) {
Slog.d(TAG, "onWakeUpStarted");
}
synchronized (mLock) {
if (mActualPowerState != POWER_STATE_AWAKE) {
mActualPowerState = POWER_STATE_AWAKE;
updatePendingBroadcastLocked();
}
}
}
/**
* Called when the device has finished waking up from sleep
* and the display has been turned on.
*/
public void onWakeUpFinished() {
if (DEBUG) {
Slog.d(TAG, "onWakeUpFinished");
}
}
/**
* Called when the device is going to sleep.
*/
public void onGoToSleepStarted(int reason) {
if (DEBUG) {
Slog.d(TAG, "onGoToSleepStarted");
}
synchronized (mLock) {
mLastGoToSleepReason = reason;
}
}
/**
* Called when the device has finished going to sleep and the
* display has been turned off.
*
* This is a good time to make transitions that we don't want the user to see,
* such as bringing the key guard to focus. There's no guarantee for this,
* however because the user could turn the device on again at any time.
* Some things may need to be protected by other mechanisms that defer screen on.
*/
public void onGoToSleepFinished() {
if (DEBUG) {
Slog.d(TAG, "onGoToSleepFinished");
}
synchronized (mLock) {
if (mActualPowerState != POWER_STATE_ASLEEP) {
mActualPowerState = POWER_STATE_ASLEEP;
if (mUserActivityPending) {
mUserActivityPending = false;
mHandler.removeMessages(MSG_USER_ACTIVITY);
}
updatePendingBroadcastLocked();
}
}
}
/**
* Called when there has been user activity.
*/
public void onUserActivity(int event, int uid) {
if (DEBUG) {
Slog.d(TAG, "onUserActivity: event=" + event + ", uid=" + uid);
}
try {
mBatteryStats.noteUserActivity(uid, event);
} catch (RemoteException ex) {
// Ignore
}
synchronized (mLock) {
if (!mUserActivityPending) {
mUserActivityPending = true;
Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY);
msg.setAsynchronous(true);
mHandler.sendMessage(msg);
}
}
}
private void updatePendingBroadcastLocked() {
if (!mBroadcastInProgress
&& mActualPowerState != POWER_STATE_UNKNOWN
&& mActualPowerState != mBroadcastedPowerState) {
mBroadcastInProgress = true;
mSuspendBlocker.acquire();
Message msg = mHandler.obtainMessage(MSG_BROADCAST);
msg.setAsynchronous(true);
mHandler.sendMessage(msg);
}
}
private void sendUserActivity() {
synchronized (mLock) {
if (!mUserActivityPending) {
return;
}
mUserActivityPending = false;
}
mPolicy.userActivity();
}
private void sendNextBroadcast() {
final int powerState;
final int goToSleepReason;
synchronized (mLock) {
if (mActualPowerState == POWER_STATE_UNKNOWN
|| mActualPowerState == mBroadcastedPowerState) {
mBroadcastInProgress = false;
mSuspendBlocker.release();
return;
}
powerState = mActualPowerState;
goToSleepReason = mLastGoToSleepReason;
mBroadcastedPowerState = powerState;
mBroadcastStartTime = SystemClock.uptimeMillis();
}
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1);
if (powerState == POWER_STATE_AWAKE) {
sendWakeUpBroadcast();
} else {
sendGoToSleepBroadcast(goToSleepReason);
}
}
private void sendWakeUpBroadcast() {
if (DEBUG) {
Slog.d(TAG, "Sending wake up broadcast.");
}
EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);
mPolicy.screenTurningOn(mScreenOnListener);
try {
ActivityManagerNative.getDefault().wakingUp();
} catch (RemoteException e) {
// ignore it
}
if (ActivityManagerNative.isSystemReady()) {
mContext.sendOrderedBroadcast(mScreenOnIntent, null,
mWakeUpBroadcastDone, mHandler, 0, null, null);
} else {
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2, 1);
sendNextBroadcast();
}
}
private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 1,
SystemClock.uptimeMillis() - mBroadcastStartTime, 1);
sendNextBroadcast();
}
};
private void sendGoToSleepBroadcast(int reason) {
if (DEBUG) {
Slog.d(TAG, "Sending go to sleep broadcast.");
}
int why = WindowManagerPolicy.OFF_BECAUSE_OF_USER;
switch (reason) {
case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:
why = WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN;
break;
case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:
why = WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT;
break;
}
EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, why, 0, 0);
mPolicy.screenTurnedOff(why);
try {
ActivityManagerNative.getDefault().goingToSleep();
} catch (RemoteException e) {
// ignore it.
}
if (ActivityManagerNative.isSystemReady()) {
mContext.sendOrderedBroadcast(mScreenOffIntent, null,
mGoToSleepBroadcastDone, mHandler, 0, null, null);
} else {
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3, 1);
sendNextBroadcast();
}
}
private final BroadcastReceiver mGoToSleepBroadcastDone = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 0,
SystemClock.uptimeMillis() - mBroadcastStartTime, 1);
sendNextBroadcast();
}
};
private final class NotifierHandler extends Handler {
public NotifierHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_USER_ACTIVITY:
sendUserActivity();
break;
case MSG_BROADCAST:
sendNextBroadcast();
break;
}
}
}
}

View File

@@ -0,0 +1,87 @@
/*
* Copyright (C) 2012 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.power;
import com.android.server.LightsService;
import java.util.concurrent.Executor;
/**
* Sets the value of a light asynchronously.
*
* This is done to avoid blocking the looper on devices for which
* setting the backlight brightness is especially slow.
*/
final class PhotonicModulator {
private static final int UNKNOWN_LIGHT_VALUE = -1;
private final Object mLock = new Object();
private final LightsService.Light mLight;
private final Executor mExecutor;
private final SuspendBlocker mSuspendBlocker;
private boolean mPendingChange;
private int mPendingLightValue;
private int mActualLightValue;
public PhotonicModulator(Executor executor, LightsService.Light light,
SuspendBlocker suspendBlocker) {
mExecutor = executor;
mLight = light;
mSuspendBlocker = suspendBlocker;
mPendingLightValue = UNKNOWN_LIGHT_VALUE;
mActualLightValue = UNKNOWN_LIGHT_VALUE;
}
/**
* Asynchronously sets the backlight brightness.
*
* @param lightValue The new light value, from 0 to 255.
*/
public void setBrightness(int lightValue) {
synchronized (mLock) {
if (lightValue != mPendingLightValue) {
mPendingLightValue = lightValue;
if (!mPendingChange) {
mPendingChange = true;
mSuspendBlocker.acquire();
mExecutor.execute(mTask);
}
}
}
}
private final Runnable mTask = new Runnable() {
@Override
public void run() {
for (;;) {
final int newLightValue;
synchronized (mLock) {
newLightValue = mPendingLightValue;
if (newLightValue == mActualLightValue) {
mSuspendBlocker.release();
mPendingChange = false;
return;
}
mActualLightValue = newLightValue;
}
mLight.setBrightness(newLightValue);
}
}
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,131 @@
/*
* Copyright (C) 2012 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.power;
import android.animation.ValueAnimator;
import android.util.IntProperty;
import android.view.Choreographer;
/**
* A custom animator that progressively updates a property value at
* a given variable rate until it reaches a particular target value.
*/
final class RampAnimator<T> {
private final T mObject;
private final IntProperty<T> mProperty;
private final Choreographer mChoreographer;
private int mCurrentValue;
private int mTargetValue;
private int mRate;
private boolean mAnimating;
private float mAnimatedValue; // higher precision copy of mCurrentValue
private long mLastFrameTimeNanos;
private boolean mFirstTime = true;
public RampAnimator(T object, IntProperty<T> property) {
mObject = object;
mProperty = property;
mChoreographer = Choreographer.getInstance();
}
/**
* Starts animating towards the specified value.
*
* If this is the first time the property is being set, the value jumps
* directly to the target.
*
* @param target The target value.
* @param rate The convergence rate, in units per second.
* @return True if the target differs from the previous target.
*/
public boolean animateTo(int target, int rate) {
// Immediately jump to the target the first time.
if (mFirstTime) {
mFirstTime = false;
mProperty.setValue(mObject, target);
mCurrentValue = target;
return true;
}
// Adjust the rate based on the closest target.
// If a faster rate is specified, then use the new rate so that we converge
// more rapidly based on the new request.
// If a slower rate is specified, then use the new rate only if the current
// value is somewhere in between the new and the old target meaning that
// we will be ramping in a different direction to get there.
// Otherwise, continue at the previous rate.
if (!mAnimating
|| rate > mRate
|| (target <= mCurrentValue && mCurrentValue <= mTargetValue)
|| (mTargetValue <= mCurrentValue && mCurrentValue <= target)) {
mRate = rate;
}
final boolean changed = (mTargetValue != target);
mTargetValue = target;
// Start animating.
if (!mAnimating && target != mCurrentValue) {
mAnimating = true;
mAnimatedValue = mCurrentValue;
mLastFrameTimeNanos = System.nanoTime();
postCallback();
}
return changed;
}
private void postCallback() {
mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mCallback, null);
}
private final Runnable mCallback = new Runnable() {
@Override // Choreographer callback
public void run() {
final long frameTimeNanos = mChoreographer.getFrameTimeNanos();
final float timeDelta = (frameTimeNanos - mLastFrameTimeNanos)
* 0.000000001f;
final float amount = timeDelta * mRate / ValueAnimator.getDurationScale();
mLastFrameTimeNanos = frameTimeNanos;
// Advance the animated value towards the target at the specified rate
// and clamp to the target. This gives us the new current value but
// we keep the animated value around to allow for fractional increments
// towards the target.
int oldCurrentValue = mCurrentValue;
if (mTargetValue > mCurrentValue) {
mAnimatedValue = Math.min(mAnimatedValue + amount, mTargetValue);
} else {
mAnimatedValue = Math.max(mAnimatedValue - amount, mTargetValue);
}
mCurrentValue = (int)Math.round(mAnimatedValue);
if (oldCurrentValue != mCurrentValue) {
mProperty.setValue(mObject, mCurrentValue);
}
if (mTargetValue != mCurrentValue) {
postCallback();
} else {
mAnimating = false;
}
}
};
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2012 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.power;
/**
* Low-level suspend blocker mechanism equivalent to holding a partial wake lock.
*
* This interface is used internally to avoid introducing internal dependencies
* on the high-level wake lock mechanism.
*/
interface SuspendBlocker {
/**
* Acquires the suspend blocker.
* Prevents the CPU from going to sleep.
*
* Calls to acquire() nest and must be matched by the same number
* of calls to release().
*/
void acquire();
/**
* Releases the suspend blocker.
* Allows the CPU to go to sleep if no other suspend blockers are held.
*
* It is an error to call release() if the suspend blocker has not been acquired.
* The system may crash.
*/
void release();
}

View File

@@ -855,7 +855,7 @@ public class WindowManagerService extends IWindowManager.Stub
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_FOREGROUND);
android.os.Process.setCanSelfBackground(false);
mPolicy.init(mContext, mService, mService, mPM);
mPolicy.init(mContext, mService, mService);
mService.mAnimator.mAboveUniverseLayer = mPolicy.getAboveUniverseLayer()
* TYPE_LAYER_MULTIPLIER
+ TYPE_LAYER_OFFSET;
@@ -910,7 +910,7 @@ public class WindowManagerService extends IWindowManager.Stub
mContext.registerReceiver(mBroadcastReceiver, filter);
mHoldingScreenWakeLock = pmc.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK
| PowerManager.ON_AFTER_RELEASE, "KEEP_SCREEN_ON_FLAG");
| PowerManager.ON_AFTER_RELEASE, PowerManager.KEEP_SCREEN_ON_FLAG_TAG);
mHoldingScreenWakeLock.setReferenceCounted(false);
mInputManager = new InputManagerService(context, mInputMonitor);
@@ -9074,16 +9074,16 @@ public class WindowManagerService extends IWindowManager.Stub
setHoldScreenLocked(mInnerFields.mHoldScreen != null);
if (!mDisplayFrozen) {
if (mInnerFields.mScreenBrightness < 0 || mInnerFields.mScreenBrightness > 1.0f) {
mPowerManager.setScreenBrightnessOverride(-1);
mPowerManager.setScreenBrightnessOverrideFromWindowManager(-1);
} else {
mPowerManager.setScreenBrightnessOverride((int)
(mInnerFields.mScreenBrightness * PowerManager.BRIGHTNESS_ON));
mPowerManager.setScreenBrightnessOverrideFromWindowManager(
toBrightnessOverride(mInnerFields.mScreenBrightness));
}
if (mInnerFields.mButtonBrightness < 0 || mInnerFields.mButtonBrightness > 1.0f) {
mPowerManager.setButtonBrightnessOverride(-1);
mPowerManager.setButtonBrightnessOverrideFromWindowManager(-1);
} else {
mPowerManager.setButtonBrightnessOverride((int)
(mInnerFields.mButtonBrightness * PowerManager.BRIGHTNESS_ON));
mPowerManager.setButtonBrightnessOverrideFromWindowManager(
toBrightnessOverride(mInnerFields.mButtonBrightness));
}
}
if (mInnerFields.mHoldScreen != mHoldingScreenOn) {
@@ -9094,8 +9094,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (mTurnOnScreen) {
if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
PowerManager.USER_ACTIVITY_EVENT_BUTTON, true);
mPowerManager.wakeUp(SystemClock.uptimeMillis());
mTurnOnScreen = false;
}
@@ -9126,6 +9125,10 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
private int toBrightnessOverride(float value) {
return (int)(value * PowerManager.BRIGHTNESS_ON);
}
void checkDrawnWindowsLocked() {
if (mWaitingForDrawn.size() > 0) {
for (int j=mWaitingForDrawn.size()-1; j>=0; j--) {

View File

@@ -120,7 +120,10 @@ static void setLight_native(JNIEnv *env, jobject clazz, int ptr,
state.flashOffMS = offMS;
state.brightnessMode = brightnessMode;
devices->lights[light]->set_light(devices->lights[light], &state);
{
ALOGD_IF_SLOW(50, "Excessive delay setting light");
devices->lights[light]->set_light(devices->lights[light], &state);
}
}
static JNINativeMethod method_table[] = {

View File

@@ -143,7 +143,7 @@ static void loadSystemIconAsSprite(JNIEnv* env, jobject contextObj, int32_t styl
enum {
WM_ACTION_PASS_TO_USER = 1,
WM_ACTION_POKE_USER_ACTIVITY = 2,
WM_ACTION_WAKE_UP = 2,
WM_ACTION_GO_TO_SLEEP = 4,
};
@@ -899,11 +899,11 @@ void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when,
android_server_PowerManagerService_goToSleep(when);
}
if (wmActions & WM_ACTION_POKE_USER_ACTIVITY) {
if (wmActions & WM_ACTION_WAKE_UP) {
#if DEBUG_INPUT_DISPATCHER_POLICY
ALOGD("handleInterceptActions: Poking user activity.");
ALOGD("handleInterceptActions: Waking up.");
#endif
android_server_PowerManagerService_userActivity(when, USER_ACTIVITY_EVENT_BUTTON);
android_server_PowerManagerService_wakeUp(when);
}
if (wmActions & WM_ACTION_PASS_TO_USER) {

View File

@@ -21,6 +21,8 @@
#include "JNIHelp.h"
#include "jni.h"
#include <ScopedUtfChars.h>
#include <limits.h>
#include <android_runtime/AndroidRuntime.h>
@@ -28,6 +30,7 @@
#include <utils/Timers.h>
#include <utils/misc.h>
#include <utils/String8.h>
#include <utils/Log.h>
#include <hardware/power.h>
#include <hardware_legacy/power.h>
#include <cutils/android_reboot.h>
@@ -42,8 +45,9 @@ namespace android {
// ----------------------------------------------------------------------------
static struct {
jmethodID goToSleep;
jmethodID userActivity;
jmethodID wakeUpFromNative;
jmethodID goToSleepFromNative;
jmethodID userActivityFromNative;
} gPowerManagerServiceClassInfo;
// ----------------------------------------------------------------------------
@@ -106,9 +110,21 @@ void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t
JNIEnv* env = AndroidRuntime::getJNIEnv();
env->CallVoidMethod(gPowerManagerServiceObj, gPowerManagerServiceClassInfo.userActivity,
nanoseconds_to_milliseconds(eventTime), false, eventType, false);
checkAndClearExceptionFromCallback(env, "userActivity");
env->CallVoidMethod(gPowerManagerServiceObj,
gPowerManagerServiceClassInfo.userActivityFromNative,
nanoseconds_to_milliseconds(eventTime), eventType, 0);
checkAndClearExceptionFromCallback(env, "userActivityFromNative");
}
}
void android_server_PowerManagerService_wakeUp(nsecs_t eventTime) {
if (gPowerManagerServiceObj) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
env->CallVoidMethod(gPowerManagerServiceObj,
gPowerManagerServiceClassInfo.wakeUpFromNative,
nanoseconds_to_milliseconds(eventTime));
checkAndClearExceptionFromCallback(env, "wakeUpFromNative");
}
}
@@ -116,9 +132,10 @@ void android_server_PowerManagerService_goToSleep(nsecs_t eventTime) {
if (gPowerManagerServiceObj) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
env->CallVoidMethod(gPowerManagerServiceObj, gPowerManagerServiceClassInfo.goToSleep,
nanoseconds_to_milliseconds(eventTime));
checkAndClearExceptionFromCallback(env, "goToSleep");
env->CallVoidMethod(gPowerManagerServiceObj,
gPowerManagerServiceClassInfo.goToSleepFromNative,
nanoseconds_to_milliseconds(eventTime), 0);
checkAndClearExceptionFromCallback(env, "goToSleepFromNative");
}
}
@@ -137,68 +154,62 @@ static void nativeInit(JNIEnv* env, jobject obj) {
}
static void nativeSetPowerState(JNIEnv* env,
jobject serviceObj, jboolean screenOn, jboolean screenBright) {
jclass clazz, jboolean screenOn, jboolean screenBright) {
AutoMutex _l(gPowerManagerLock);
gScreenOn = screenOn;
gScreenBright = screenBright;
}
static void nativeStartSurfaceFlingerAnimation(JNIEnv* env,
jobject obj, jint mode) {
// this is not handled by surfaceflinger anymore
static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameStr) {
ScopedUtfChars name(env, nameStr);
acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str());
}
static void nativeAcquireWakeLock(JNIEnv *env, jobject clazz, jint lock, jstring idObj) {
if (idObj == NULL) {
jniThrowNullPointerException(env, "id is null");
return;
}
const char *id = env->GetStringUTFChars(idObj, NULL);
acquire_wake_lock(lock, id);
env->ReleaseStringUTFChars(idObj, id);
static void nativeReleaseSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameStr) {
ScopedUtfChars name(env, nameStr);
release_wake_lock(name.c_str());
}
static void nativeReleaseWakeLock(JNIEnv *env, jobject clazz, jstring idObj) {
if (idObj == NULL) {
jniThrowNullPointerException(env, "id is null");
return ;
}
const char *id = env->GetStringUTFChars(idObj, NULL);
release_wake_lock(id);
env->ReleaseStringUTFChars(idObj, id);
}
static int nativeSetScreenState(JNIEnv *env, jobject clazz, jboolean on) {
static void nativeSetScreenState(JNIEnv *env, jclass clazz, jboolean on) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
if (on) {
autosuspend_disable();
{
ALOGD_IF_SLOW(50, "Excessive delay in autosuspend_disable() while turning screen on");
autosuspend_disable();
}
if (gPowerModule) {
ALOGD_IF_SLOW(10, "Excessive delay in setInteractive(true) while turning screen on");
gPowerModule->setInteractive(gPowerModule, true);
}
s->unblank();
{
ALOGD_IF_SLOW(20, "Excessive delay in unblank() while turning screen on");
s->unblank();
}
} else {
s->blank();
{
ALOGD_IF_SLOW(20, "Excessive delay in blank() while turning screen off");
s->blank();
}
if (gPowerModule) {
ALOGD_IF_SLOW(10, "Excessive delay in setInteractive(false) while turning screen off");
gPowerModule->setInteractive(gPowerModule, false);
}
autosuspend_enable();
}
return 0;
{
ALOGD_IF_SLOW(50, "Excessive delay in autosuspend_enable() while turning screen off");
autosuspend_enable();
}
}
}
static void nativeShutdown(JNIEnv *env, jobject clazz) {
static void nativeShutdown(JNIEnv *env, jclass clazz) {
android_reboot(ANDROID_RB_POWEROFF, 0, 0);
}
static void nativeReboot(JNIEnv *env, jobject clazz, jstring reason) {
static void nativeReboot(JNIEnv *env, jclass clazz, jstring reason) {
if (reason == NULL) {
android_reboot(ANDROID_RB_RESTART, 0, 0);
} else {
@@ -218,13 +229,11 @@ static JNINativeMethod gPowerManagerServiceMethods[] = {
(void*) nativeInit },
{ "nativeSetPowerState", "(ZZ)V",
(void*) nativeSetPowerState },
{ "nativeStartSurfaceFlingerAnimation", "(I)V",
(void*) nativeStartSurfaceFlingerAnimation },
{ "nativeAcquireWakeLock", "(ILjava/lang/String;)V",
(void*) nativeAcquireWakeLock },
{ "nativeReleaseWakeLock", "(Ljava/lang/String;)V",
(void*) nativeReleaseWakeLock },
{ "nativeSetScreenState", "(Z)I",
{ "nativeAcquireSuspendBlocker", "(Ljava/lang/String;)V",
(void*) nativeAcquireSuspendBlocker },
{ "nativeReleaseSuspendBlocker", "(Ljava/lang/String;)V",
(void*) nativeReleaseSuspendBlocker },
{ "nativeSetScreenState", "(Z)V",
(void*) nativeSetScreenState },
{ "nativeShutdown", "()V",
(void*) nativeShutdown },
@@ -254,11 +263,14 @@ int register_android_server_PowerManagerService(JNIEnv* env) {
jclass clazz;
FIND_CLASS(clazz, "com/android/server/power/PowerManagerService");
GET_METHOD_ID(gPowerManagerServiceClassInfo.goToSleep, clazz,
"goToSleep", "(J)V");
GET_METHOD_ID(gPowerManagerServiceClassInfo.wakeUpFromNative, clazz,
"wakeUpFromNative", "(J)V");
GET_METHOD_ID(gPowerManagerServiceClassInfo.userActivity, clazz,
"userActivity", "(JZIZ)V");
GET_METHOD_ID(gPowerManagerServiceClassInfo.goToSleepFromNative, clazz,
"goToSleepFromNative", "(JI)V");
GET_METHOD_ID(gPowerManagerServiceClassInfo.userActivityFromNative, clazz,
"userActivityFromNative", "(JII)V");
// Initialize
for (int i = 0; i <= USER_ACTIVITY_EVENT_LAST; i++) {

View File

@@ -27,6 +27,7 @@ namespace android {
extern bool android_server_PowerManagerService_isScreenOn();
extern bool android_server_PowerManagerService_isScreenBright();
extern void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType);
extern void android_server_PowerManagerService_wakeUp(nsecs_t eventTime);
extern void android_server_PowerManagerService_goToSleep(nsecs_t eventTime);
} // namespace android

View File

@@ -16,32 +16,15 @@
package com.android.statusbartest;
import android.app.ListActivity;
import android.app.Notification;
import android.app.NotificationManager;
import android.widget.ArrayAdapter;
import android.view.View;
import android.os.Binder;
import android.os.IBinder;
import android.os.IPowerManager;
import android.widget.ListView;
import android.content.Intent;
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.StatusBarManager;
import android.os.RemoteException;
import android.os.Vibrator;
import android.os.Bundle;
import android.os.Handler;
import android.os.LocalPowerManager;
import android.os.ServiceManager;
import android.util.Log;
import android.net.Uri;
import android.os.SystemClock;
import android.widget.RemoteViews;
import android.widget.Toast;
import android.os.PowerManager;
public class PowerTest extends TestActivity
@@ -101,6 +84,28 @@ public class PowerTest extends TestActivity
mProx.release(PowerManager.WAIT_FOR_PROXIMITY_NEGATIVE);
}
},
new Test("Enable proximity, wait 5 seconds then disable") {
public void run() {
mProx.acquire();
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mProx.release();
}
}, 5000);
}
},
new Test("Enable proximity, wait 5 seconds then disable (WAIT_FOR_PROXIMITY_NEGATIVE)") {
public void run() {
mProx.acquire();
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mProx.release(PowerManager.WAIT_FOR_PROXIMITY_NEGATIVE);
}
}, 5000);
}
},
new Test("Touch events don't poke") {
public void run() {
mPokeState |= LocalPowerManager.POKE_LOCK_IGNORE_TOUCH_EVENTS;

View File

@@ -440,7 +440,7 @@ public final class BridgeContext extends Context {
}
if (POWER_SERVICE.equals(service)) {
return new PowerManager(new BridgePowerManager(), new Handler());
return new PowerManager(this, new BridgePowerManager(), new Handler());
}
throw new UnsupportedOperationException("Unsupported Service: " + service);

View File

@@ -39,7 +39,7 @@ public class BridgePowerManager implements IPowerManager {
}
@Override
public void acquireWakeLock(int arg0, IBinder arg1, String arg2, WorkSource arg3)
public void acquireWakeLock(IBinder arg0, int arg1, String arg2, WorkSource arg3)
throws RemoteException {
// pass for now.
}
@@ -55,18 +55,7 @@ public class BridgePowerManager implements IPowerManager {
}
@Override
public int getSupportedWakeLockFlags() throws RemoteException {
// pass for now.
return 0;
}
@Override
public void goToSleep(long arg0) throws RemoteException {
// pass for now.
}
@Override
public void goToSleepWithReason(long arg0, int arg1) throws RemoteException {
public void goToSleep(long arg0, int arg1) throws RemoteException {
// pass for now.
}
@@ -91,17 +80,17 @@ public class BridgePowerManager implements IPowerManager {
}
@Override
public void setAutoBrightnessAdjustment(float arg0) throws RemoteException {
public void setTemporaryScreenAutoBrightnessAdjustmentSettingOverride(float arg0) throws RemoteException {
// pass for now.
}
@Override
public void setBacklightBrightness(int arg0) throws RemoteException {
public void setTemporaryScreenBrightnessSettingOverride(int arg0) throws RemoteException {
// pass for now.
}
@Override
public void setMaximumScreenOffTimeount(int arg0) throws RemoteException {
public void setMaximumScreenOffTimeoutFromDeviceAdmin(int arg0) throws RemoteException {
// pass for now.
}
@@ -121,12 +110,18 @@ public class BridgePowerManager implements IPowerManager {
}
@Override
public void userActivity(long arg0, boolean arg1) throws RemoteException {
public boolean isWakeLockLevelSupported(int level) throws RemoteException {
// pass for now.
return true;
}
@Override
public void userActivity(long time, int event, int flags) throws RemoteException {
// pass for now.
}
@Override
public void userActivityWithForce(long arg0, boolean arg1, boolean arg2) throws RemoteException {
public void wakeUp(long time) throws RemoteException {
// pass for now.
}
}