diff options
author | Jeff Brown <jeffbrown@google.com> | 2012-10-07 23:43:59 -0700 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2012-10-07 23:43:59 -0700 |
commit | 08e255c9b892228d794d77e417aef78e0de2e41d (patch) | |
tree | 36e00d3c6f16877c75fef1989c337c5f01806949 /services | |
parent | 8c8487fde272ff884db7951bb5207a7f7c46a49e (diff) | |
parent | f9205adb415cf87a9c4956e0b850c831801cc1f3 (diff) | |
download | frameworks_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')
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 { /** |