am 9302251e: Merge "Reduce screen on latency, eliminate flashes." into jb-mr1-dev
* commit '9302251e3a09810164895237a6a2e8ac4987c3c0': Reduce screen on latency, eliminate flashes.
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user