summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2012-10-07 23:43:59 -0700
committerAndroid Git Automerger <android-git-automerger@android.com>2012-10-07 23:43:59 -0700
commit08e255c9b892228d794d77e417aef78e0de2e41d (patch)
tree36e00d3c6f16877c75fef1989c337c5f01806949 /services
parent8c8487fde272ff884db7951bb5207a7f7c46a49e (diff)
parentf9205adb415cf87a9c4956e0b850c831801cc1f3 (diff)
downloadframeworks_base-08e255c9b892228d794d77e417aef78e0de2e41d.zip
frameworks_base-08e255c9b892228d794d77e417aef78e0de2e41d.tar.gz
frameworks_base-08e255c9b892228d794d77e417aef78e0de2e41d.tar.bz2
am f9205adb: am 3a8effb8: am 9302251e: Merge "Reduce screen on latency, eliminate flashes." into jb-mr1-dev
* commit 'f9205adb415cf87a9c4956e0b850c831801cc1f3': Reduce screen on latency, eliminate flashes.
Diffstat (limited to 'services')
-rw-r--r--services/java/com/android/server/power/DisplayPowerController.java72
-rw-r--r--services/java/com/android/server/power/DisplayPowerRequest.java13
-rw-r--r--services/java/com/android/server/power/DisplayPowerState.java25
-rw-r--r--services/java/com/android/server/power/ElectronBeam.java74
-rw-r--r--services/java/com/android/server/power/ScreenOnBlocker.java2
5 files changed, 116 insertions, 70 deletions
diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java
index a1c1fa6..25d2944 100644
--- a/services/java/com/android/server/power/DisplayPowerController.java
+++ b/services/java/com/android/server/power/DisplayPowerController.java
@@ -271,6 +271,12 @@ final class DisplayPowerController {
// When the screen turns on again, we report user activity to the power manager.
private boolean mScreenOffBecauseOfProximity;
+ // True if the screen on is being blocked.
+ private boolean mScreenOnWasBlocked;
+
+ // The elapsed real time when the screen on was blocked.
+ private long mScreenOnBlockStartRealTime;
+
// Set to true if the light sensor is enabled.
private boolean mLightSensorEnabled;
@@ -513,7 +519,7 @@ final class DisplayPowerController {
final Executor executor = AsyncTask.THREAD_POOL_EXECUTOR;
Display display = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
mPowerState = new DisplayPowerState(
- mElectronBeamAnimatesBacklightConfig ? null : new ElectronBeam(display),
+ new ElectronBeam(display),
new PhotonicModulator(executor,
mLights.getLight(LightsService.LIGHT_ID_BACKLIGHT),
mSuspendBlocker));
@@ -553,7 +559,6 @@ final class DisplayPowerController {
final boolean mustNotify;
boolean mustInitialize = false;
boolean updateAutoBrightness = mTwilightChanged;
- boolean screenOnWasBlocked = false;
mTwilightChanged = false;
synchronized (mLock) {
@@ -662,18 +667,24 @@ final class DisplayPowerController {
// 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()) {
- if (mPowerRequest.blockScreenOn && !mPowerState.isScreenOn()) {
- if (DEBUG) {
- Slog.d(TAG, "Blocked screen on while screen currently off.");
- }
- screenOnWasBlocked = true;
+ // Turn the screen on. The contents of the screen may not yet
+ // be visible if the electron beam has not been dismissed because
+ // its last frame of animation is solid black.
+ setScreenOn(true);
+
+ if (mPowerRequest.blockScreenOn
+ && mPowerState.getElectronBeamLevel() == 0.0f) {
+ blockScreenOn();
} else {
- setScreenOn(true);
+ unblockScreenOn();
if (USE_ELECTRON_BEAM_ON_ANIMATION) {
if (!mElectronBeamOnAnimator.isStarted()) {
if (mPowerState.getElectronBeamLevel() == 1.0f) {
mPowerState.dismissElectronBeam();
- } else if (mPowerState.prepareElectronBeam(true)) {
+ } else if (mPowerState.prepareElectronBeam(
+ mElectronBeamAnimatesBacklightConfig ?
+ ElectronBeam.MODE_BLANK :
+ ElectronBeam.MODE_WARM_UP)) {
mElectronBeamOnAnimator.start();
} else {
mElectronBeamOnAnimator.end();
@@ -684,22 +695,6 @@ final class DisplayPowerController {
mPowerState.dismissElectronBeam();
}
}
- } else {
- // FIXME: If the electron beam off animation is playing then we have a bit
- // of a problem. The window manager policy would only have requested
- // to block screen on if it was about to start preparing the keyguard.
- // It's already too late to do anything about that. Ideally we would
- // let the animation play out first but that would require making
- // some pretty deep changes to the power manager and we don't have
- // time just now. For now, short-circuit the animation and get ready.
- if (mPowerRequest.blockScreenOn) {
- if (DEBUG) {
- Slog.d(TAG, "Blocked screen on while screen off animation running.");
- }
- screenOnWasBlocked = true;
- setScreenOn(false);
- mElectronBeamOffAnimator.end();
- }
}
} else {
// Want screen off.
@@ -708,7 +703,10 @@ final class DisplayPowerController {
if (!mElectronBeamOffAnimator.isStarted()) {
if (mPowerState.getElectronBeamLevel() == 0.0f) {
setScreenOn(false);
- } else if (mPowerState.prepareElectronBeam(false)
+ } else if (mPowerState.prepareElectronBeam(
+ mElectronBeamAnimatesBacklightConfig ?
+ ElectronBeam.MODE_BLANK :
+ ElectronBeam.MODE_COOL_DOWN)
&& mPowerState.isScreenOn()) {
mElectronBeamOffAnimator.start();
} else {
@@ -723,7 +721,7 @@ final class DisplayPowerController {
// We mostly care about the screen state here, ignoring brightness changes
// which will be handled asynchronously.
if (mustNotify
- && !screenOnWasBlocked
+ && !mScreenOnWasBlocked
&& !mElectronBeamOnAnimator.isStarted()
&& !mElectronBeamOffAnimator.isStarted()
&& mPowerState.waitUntilClean(mCleanListener)) {
@@ -740,6 +738,26 @@ final class DisplayPowerController {
}
}
+ private void blockScreenOn() {
+ if (!mScreenOnWasBlocked) {
+ mScreenOnWasBlocked = true;
+ if (DEBUG) {
+ Slog.d(TAG, "Blocked screen on.");
+ mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
+ }
+ }
+ }
+
+ private void unblockScreenOn() {
+ if (mScreenOnWasBlocked) {
+ mScreenOnWasBlocked = false;
+ if (DEBUG) {
+ Slog.d(TAG, "Unblocked screen on after " +
+ (SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime) + " ms");
+ }
+ }
+ }
+
private void setScreenOn(boolean on) {
if (!mPowerState.isScreenOn() == on) {
mPowerState.setScreenOn(on);
diff --git a/services/java/com/android/server/power/DisplayPowerRequest.java b/services/java/com/android/server/power/DisplayPowerRequest.java
index 5f94414..22f17d7 100644
--- a/services/java/com/android/server/power/DisplayPowerRequest.java
+++ b/services/java/com/android/server/power/DisplayPowerRequest.java
@@ -52,11 +52,14 @@ final class DisplayPowerRequest {
// If true, enables automatic brightness control.
public boolean useAutoBrightness;
- // If true, prevents the screen from turning on if it is currently off.
- // The display does not enter a "ready" state if this flag is true and the screen
- // is off and is being prevented from turning on. The window manager policy blocks
- // screen on while it prepares the keyguard to prevent the user from seeing
- // intermediate updates.
+ // If true, prevents the screen from completely turning on if it is currently off.
+ // The display does not enter a "ready" state if this flag is true and screen on is
+ // blocked. The window manager policy blocks screen on while it prepares the keyguard to
+ // prevent the user from seeing intermediate updates.
+ //
+ // Technically, we may not block the screen itself from turning on (because that introduces
+ // extra unnecessary latency) but we do prevent content on screen from becoming
+ // visible to the user.
public boolean blockScreenOn;
public DisplayPowerRequest() {
diff --git a/services/java/com/android/server/power/DisplayPowerState.java b/services/java/com/android/server/power/DisplayPowerState.java
index dba45b3..f6ce7a7 100644
--- a/services/java/com/android/server/power/DisplayPowerState.java
+++ b/services/java/com/android/server/power/DisplayPowerState.java
@@ -50,7 +50,7 @@ final class DisplayPowerState {
private static final int DIRTY_BRIGHTNESS = 1 << 2;
private final Choreographer mChoreographer;
- private final ElectronBeam mElectronBeam; // may be null if only animating backlights
+ private final ElectronBeam mElectronBeam;
private final PhotonicModulator mScreenBrightnessModulator;
private int mDirty;
@@ -130,26 +130,19 @@ final class DisplayPowerState {
* 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.
+ * @param mode The electron beam animation mode to prepare.
* @return True if the electron beam was prepared.
*/
- public boolean prepareElectronBeam(boolean warmUp) {
- if (mElectronBeam != null) {
- boolean success = mElectronBeam.prepare(warmUp);
- invalidate(DIRTY_ELECTRON_BEAM);
- return success;
- } else {
- return true;
- }
+ public boolean prepareElectronBeam(int mode) {
+ invalidate(DIRTY_ELECTRON_BEAM);
+ return mElectronBeam.prepare(mode);
}
/**
* Dismisses the electron beam surface.
*/
public void dismissElectronBeam() {
- if (mElectronBeam != null) {
- mElectronBeam.dismiss();
- }
+ mElectronBeam.dismiss();
}
/**
@@ -230,9 +223,7 @@ final class DisplayPowerState {
pw.println(" mScreenBrightness=" + mScreenBrightness);
pw.println(" mElectronBeamLevel=" + mElectronBeamLevel);
- if (mElectronBeam != null) {
- mElectronBeam.dump(pw);
- }
+ mElectronBeam.dump(pw);
}
private void invalidate(int dirty) {
@@ -251,7 +242,7 @@ final class DisplayPowerState {
PowerManagerService.nativeSetScreenState(false);
}
- if ((mDirty & DIRTY_ELECTRON_BEAM) != 0 && mElectronBeam != null) {
+ if ((mDirty & DIRTY_ELECTRON_BEAM) != 0) {
mElectronBeam.draw(mElectronBeamLevel);
}
diff --git a/services/java/com/android/server/power/ElectronBeam.java b/services/java/com/android/server/power/ElectronBeam.java
index 0c68997..8c242f7 100644
--- a/services/java/com/android/server/power/ElectronBeam.java
+++ b/services/java/com/android/server/power/ElectronBeam.java
@@ -26,7 +26,6 @@ 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;
@@ -41,12 +40,13 @@ import java.nio.FloatBuffer;
/**
* Bzzzoooop! *crackle*
- *
+ * <p>
* Animates a screen transition from on to off or off to on by applying
* some GL transformations to a screenshot.
- *
+ * </p><p>
* This component must only be created or accessed by the {@link Looper} thread
* that belongs to the {@link DisplayPowerController}.
+ * </p>
*/
final class ElectronBeam {
private static final String TAG = "ElectronBeam";
@@ -65,7 +65,7 @@ final class ElectronBeam {
// Set to true when the animation context has been fully prepared.
private boolean mPrepared;
- private boolean mWarmUp;
+ private int mMode;
private final Display mDisplay;
private final DisplayInfo mDisplayInfo = new DisplayInfo();
@@ -90,6 +90,10 @@ final class ElectronBeam {
private final FloatBuffer mVertexBuffer = createNativeFloatBuffer(8);
private final FloatBuffer mTexCoordBuffer = createNativeFloatBuffer(8);
+ public static final int MODE_WARM_UP = 0;
+ public static final int MODE_COOL_DOWN = 1;
+ public static final int MODE_BLANK = 2;
+
public ElectronBeam(Display display) {
mDisplay = display;
}
@@ -98,16 +102,15 @@ final class 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.
+ * @param mode The desired mode for the upcoming animation.
* @return True if the electron beam is ready, false if it is uncontrollable.
*/
- public boolean prepare(boolean warmUp) {
+ public boolean prepare(int mode) {
if (DEBUG) {
- Slog.d(TAG, "prepare: warmUp=" + warmUp);
+ Slog.d(TAG, "prepare: mode=" + mode);
}
- mWarmUp = warmUp;
+ mMode = mode;
// Get the display size and adjust it for rotation.
mDisplay.getDisplayInfo(mDisplayInfo);
@@ -123,17 +126,28 @@ final class ElectronBeam {
}
// Prepare the surface for drawing.
- if (!createEglContext()
- || !createEglSurface()
- || !captureScreenshotTextureAndSetViewport()) {
+ if (!tryPrepare()) {
dismiss();
return false;
}
+ // Done.
mPrepared = true;
return true;
}
+ private boolean tryPrepare() {
+ if (createSurface()) {
+ if (mMode == MODE_BLANK) {
+ return true;
+ }
+ return createEglContext()
+ && createEglSurface()
+ && captureScreenshotTextureAndSetViewport();
+ }
+ return false;
+ }
+
/**
* Dismisses the electron beam animation surface and cleans up.
*
@@ -148,6 +162,7 @@ final class ElectronBeam {
destroyScreenshotTexture();
destroyEglSurface();
+ destroySurface();
mPrepared = false;
}
@@ -163,6 +178,14 @@ final class ElectronBeam {
Slog.d(TAG, "drawFrame: level=" + level);
}
+ if (!mPrepared) {
+ return false;
+ }
+
+ if (mMode == MODE_BLANK) {
+ return showSurface(1.0f - level);
+ }
+
if (!attachEglContext()) {
return false;
}
@@ -185,8 +208,7 @@ final class ElectronBeam {
} finally {
detachEglContext();
}
-
- return showEglSurface();
+ return showSurface(1.0f);
}
/**
@@ -217,7 +239,7 @@ final class ElectronBeam {
// 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);
+ mMode == MODE_WARM_UP ? 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,
@@ -251,7 +273,7 @@ final class ElectronBeam {
GLES10.glColorMask(true, true, true, true);
// draw the white highlight (we use the last vertices)
- if (!mWarmUp) {
+ if (mMode == MODE_COOL_DOWN) {
GLES10.glColor4f(ag, ag, ag, 1.0f);
GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
}
@@ -472,7 +494,7 @@ final class ElectronBeam {
}
}*/
- private boolean createEglSurface() {
+ private boolean createSurface() {
if (mSurfaceSession == null) {
mSurfaceSession = new SurfaceSession();
}
@@ -481,9 +503,15 @@ final class ElectronBeam {
try {
if (mSurface == null) {
try {
+ int flags;
+ if (mMode == MODE_BLANK) {
+ flags = Surface.FX_SURFACE_DIM | Surface.HIDDEN;
+ } else {
+ flags = Surface.OPAQUE | Surface.HIDDEN;
+ }
mSurface = new Surface(mSurfaceSession,
"ElectronBeam", mDisplayWidth, mDisplayHeight,
- PixelFormat.OPAQUE, Surface.OPAQUE | Surface.HIDDEN);
+ PixelFormat.OPAQUE, flags);
} catch (Surface.OutOfResourcesException ex) {
Slog.e(TAG, "Unable to create surface.", ex);
return false;
@@ -514,7 +542,10 @@ final class ElectronBeam {
} finally {
Surface.closeTransaction();
}
+ return true;
+ }
+ private boolean createEglSurface() {
if (mEglSurface == null) {
int[] eglSurfaceAttribList = new int[] {
EGL14.EGL_NONE
@@ -536,7 +567,9 @@ final class ElectronBeam {
}
mEglSurface = null;
}
+ }
+ private void destroySurface() {
if (mSurface != null) {
Surface.openTransaction();
try {
@@ -549,11 +582,12 @@ final class ElectronBeam {
}
}
- private boolean showEglSurface() {
+ private boolean showSurface(float alpha) {
if (!mSurfaceVisible) {
Surface.openTransaction();
try {
mSurface.setLayer(ELECTRON_BEAM_LAYER);
+ mSurface.setAlpha(alpha);
mSurface.show();
} finally {
Surface.closeTransaction();
@@ -643,7 +677,7 @@ final class ElectronBeam {
pw.println();
pw.println("Electron Beam State:");
pw.println(" mPrepared=" + mPrepared);
- pw.println(" mWarmUp=" + mWarmUp);
+ pw.println(" mMode=" + mMode);
pw.println(" mDisplayLayerStack=" + mDisplayLayerStack);
pw.println(" mDisplayRotation=" + mDisplayRotation);
pw.println(" mDisplayWidth=" + mDisplayWidth);
diff --git a/services/java/com/android/server/power/ScreenOnBlocker.java b/services/java/com/android/server/power/ScreenOnBlocker.java
index 2bf0bcf..dbbbc6d 100644
--- a/services/java/com/android/server/power/ScreenOnBlocker.java
+++ b/services/java/com/android/server/power/ScreenOnBlocker.java
@@ -18,7 +18,7 @@ package com.android.server.power;
/**
* Low-level screen on blocker mechanism which is used to keep the screen off
- * until the window manager is ready to show new content.
+ * or the contents of the screen hidden until the window manager is ready to show new content.
*/
interface ScreenOnBlocker {
/**