OSDN Git Service

AOD: Fix navbar flicker when transitioning to AOD
authorAdrian Roos <roosa@google.com>
Fri, 11 Aug 2017 17:43:17 +0000 (19:43 +0200)
committerSelim Cinek <cinek@google.com>
Fri, 11 Aug 2017 21:29:35 +0000 (14:29 -0700)
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.

packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java

index 302bc2d..d374d68 100644 (file)
@@ -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) {
index 846ec27..63f5d97 100644 (file)
@@ -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;
         }
     }
 }
index e54c792..c787eff 100644 (file)
@@ -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