From 0791d97e117f4ebbb960852c1c5aa6c26de089b0 Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Mon, 26 Mar 2018 13:32:16 -0700 Subject: [PATCH] Fix flickering when switching display power modes So far we've been Waiting for the next frame but it doesn't mean that it will be visible on the screen. We're usually rendering with 2 buffers and it's possible that we'll switch the display power mode before anything has hit the display. Increased the timeout for now until we have a better alternative. Change-Id: I63afc8a9139a4ccbba4f16f5569717e22217da9a Fixes: 72527083 Test: manual Test: packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java --- .../statusbar/phone/ScrimController.java | 20 ++++++++++++------- .../statusbar/phone/ScrimControllerTest.java | 6 ++---- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index cfc0cc6207c37..7a6e98da8b35e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -148,7 +148,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo private float mNotificationDensity; // Scrim blanking callbacks - private Choreographer.FrameCallback mPendingFrameCallback; + private Runnable mPendingFrameCallback; private Runnable mBlankingTransitionRunnable; private final WakeLock mWakeLock; @@ -240,7 +240,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo // Cancel blanking transitions that were pending before we requested a new state if (mPendingFrameCallback != null) { - Choreographer.getInstance().removeFrameCallback(mPendingFrameCallback); + mScrimBehind.removeCallbacks(mPendingFrameCallback); mPendingFrameCallback = null; } if (getHandler().hasCallbacks(mBlankingTransitionRunnable)) { @@ -278,7 +278,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo // with too many things at this case, in order to not skip the initial frames. mScrimInFront.postOnAnimationDelayed(this::scheduleUpdate, 16); mAnimationDelay = StatusBar.FADE_KEYGUARD_START_DELAY; - } else if (!mDozeParameters.getAlwaysOn() && oldState == ScrimState.AOD + } else if ((!mDozeParameters.getAlwaysOn() && oldState == ScrimState.AOD) || (mState == ScrimState.AOD && !mDozeParameters.getDisplayNeedsBlanking())) { // Scheduling a frame isn't enough when: // • Leaving doze and we need to modify scrim color immediately @@ -727,7 +727,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo // Notify callback that the screen is completely black and we're // ready to change the display power mode - mPendingFrameCallback = frameTimeNanos -> { + mPendingFrameCallback = () -> { if (mCallback != null) { mCallback.onDisplayBlanked(); mScreenBlankingCallbackCalled = true; @@ -743,7 +743,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo // Setting power states can happen after we push out the frame. Make sure we // stay fully opaque until the power state request reaches the lower levels. - final int delay = mScreenOn ? 16 : 500; + final int delay = mScreenOn ? 32 : 500; if (DEBUG) { Log.d(TAG, "Fading out scrims with delay: " + delay); } @@ -752,9 +752,15 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo doOnTheNextFrame(mPendingFrameCallback); } + /** + * Executes a callback after the frame has hit the display. + * @param callback What to run. + */ @VisibleForTesting - protected void doOnTheNextFrame(Choreographer.FrameCallback callback) { - Choreographer.getInstance().postFrameCallback(callback); + protected void doOnTheNextFrame(Runnable callback) { + // Just calling View#postOnAnimation isn't enough because the frame might not have reached + // the display yet. A timeout is the safest solution. + mScrimBehind.postOnAnimationDelayed(callback, 32 /* delayMillis */); } @VisibleForTesting diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java index 45845fc147a6e..7743c6b443a54 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java @@ -39,10 +39,8 @@ import android.os.Looper; import android.support.test.filters.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; -import android.view.Choreographer; import android.view.View; -import com.android.internal.util.Preconditions; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.ScrimView; @@ -557,8 +555,8 @@ public class ScrimControllerTest extends SysuiTestCase { * @param callback What to execute. */ @Override - protected void doOnTheNextFrame(Choreographer.FrameCallback callback) { - callback.doFrame(0); + protected void doOnTheNextFrame(Runnable callback) { + callback.run(); } }