From 8db9311cb683c58b7d61f812ae4975feca926aa4 Mon Sep 17 00:00:00 2001 From: Adrian Roos Date: Fri, 11 Aug 2017 19:43:17 +0200 Subject: [PATCH] AOD: Fix navbar flicker when transitioning to AOD Under certain circumstances, the transition to AOD can happen before the navigation bar gets a chance to hide itself, which happens in a traversal. To work around this, post turning the screen on such that it only happens after the next traversal. Change-Id: I178b9394e7cc6baa8e9552c9819c3ce9b044defb Fixes: 64599221 Test: Open Whatsapp / Gmail, turn off screen, verify navbar does not flicker. --- .../android/systemui/doze/DozeFactory.java | 6 +--- .../systemui/doze/DozeScreenState.java | 34 ++++++++++++++++-- .../systemui/doze/DozeScreenStateTest.java | 35 ++++++++++++++++++- 3 files changed, 67 insertions(+), 8 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java index 302bc2d38f64e..d374d68a456bb 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java @@ -64,17 +64,13 @@ public class DozeFactory { createDozeTriggers(context, sensorManager, host, alarmManager, config, params, handler, wakeLock, machine), createDozeUi(context, host, wakeLock, machine, handler, alarmManager), - createDozeScreenState(wrappedService), + new DozeScreenState(wrappedService, handler), createDozeScreenBrightness(context, wrappedService, sensorManager, host, handler), }); return machine; } - private DozeMachine.Part createDozeScreenState(DozeMachine.Service service) { - return new DozeScreenState(service); - } - private DozeMachine.Part createDozeScreenBrightness(Context context, DozeMachine.Service service, SensorManager sensorManager, DozeHost host, Handler handler) { diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java index 846ec27c451e0..63f5d97542f68 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java @@ -16,7 +16,7 @@ package com.android.systemui.doze; -import android.content.Context; +import android.os.Handler; import android.view.Display; /** @@ -24,16 +24,46 @@ import android.view.Display; */ public class DozeScreenState implements DozeMachine.Part { private final DozeMachine.Service mDozeService; + private final Handler mHandler; + private int mPendingScreenState = Display.STATE_UNKNOWN; + private Runnable mApplyPendingScreenState = this::applyPendingScreenState; - public DozeScreenState(DozeMachine.Service service) { + public DozeScreenState(DozeMachine.Service service, Handler handler) { mDozeService = service; + mHandler = handler; } @Override public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) { int screenState = newState.screenState(); + if (screenState == Display.STATE_UNKNOWN) { + // We'll keep it in the existing state + return; + } + boolean messagePending = mHandler.hasCallbacks(mApplyPendingScreenState); + if (messagePending || oldState == DozeMachine.State.INITIALIZED) { + // During initialization, we hide the navigation bar. That is however only applied after + // a traversal; setting the screen state here is immediate however, so it can happen + // that the screen turns on again before the navigation bar is hidden. To work around + // that, wait for a traversal to happen before applying the initial screen state. + mPendingScreenState = screenState; + if (!messagePending) { + mHandler.post(mApplyPendingScreenState); + } + return; + } + applyScreenState(screenState); + } + + private void applyPendingScreenState() { + applyScreenState(mPendingScreenState); + mPendingScreenState = Display.STATE_UNKNOWN; + } + + private void applyScreenState(int screenState) { if (screenState != Display.STATE_UNKNOWN) { mDozeService.setDozeScreenState(screenState); + mPendingScreenState = Display.STATE_UNKNOWN; } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java index e54c7924fc666..c787eff8a6ecd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java @@ -24,7 +24,14 @@ import static com.android.systemui.doze.DozeMachine.State.INITIALIZED; import static com.android.systemui.doze.DozeMachine.State.UNINITIALIZED; import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.view.Display; @@ -41,11 +48,13 @@ public class DozeScreenStateTest extends SysuiTestCase { DozeServiceFake mServiceFake; DozeScreenState mScreen; + private ImmediateHandler mHandler; @Before public void setUp() throws Exception { mServiceFake = new DozeServiceFake(); - mScreen = new DozeScreenState(mServiceFake); + mHandler = spy(new ImmediateHandler(Looper.getMainLooper())); + mScreen = new DozeScreenState(mServiceFake, mHandler); } @Test @@ -95,4 +104,28 @@ public class DozeScreenStateTest extends SysuiTestCase { assertEquals(Display.STATE_OFF, mServiceFake.screenState); } + @Test + public void test_postedToHandler() { + mScreen.transitionTo(UNINITIALIZED, INITIALIZED); + mScreen.transitionTo(INITIALIZED, DOZE_AOD); + + verify(mHandler).sendMessageAtTime(any(), anyLong()); + } + + private static class ImmediateHandler extends Handler { + + public ImmediateHandler(Looper looper) { + super(looper); + } + + @Override + public boolean sendMessageAtTime(Message msg, long uptimeMillis) { + Runnable callback = msg.getCallback(); + if (callback != null) { + callback.run(); + return false; + } + return super.sendMessageAtTime(msg, uptimeMillis); + } + } } \ No newline at end of file