Merge "AOD: Fix crash when AOD is stopped immediately after starting" into oc-mr1-dev am: 07168bf44b
am: b32f14c2e9
Change-Id: I98f8eb4bd3a81e1d48b82c925dbf5cf5ac562de4
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
index 63f5d97..02a725d 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
@@ -36,10 +36,21 @@
@Override
public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
int screenState = newState.screenState();
+
+ if (newState == DozeMachine.State.FINISH) {
+ // Make sure not to apply the screen state after DozeService was destroyed.
+ mPendingScreenState = Display.STATE_UNKNOWN;
+ mHandler.removeCallbacks(mApplyPendingScreenState);
+
+ applyScreenState(screenState);
+ return;
+ }
+
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
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 c787eff..521d2e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
@@ -20,23 +20,22 @@
import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD;
import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSING;
import static com.android.systemui.doze.DozeMachine.State.DOZE_REQUEST_PULSE;
+import static com.android.systemui.doze.DozeMachine.State.FINISH;
import static com.android.systemui.doze.DozeMachine.State.INITIALIZED;
import static com.android.systemui.doze.DozeMachine.State.UNINITIALIZED;
+import static com.android.systemui.utils.os.FakeHandler.Mode.QUEUEING;
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 static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
-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;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.utils.os.FakeHandler;
import org.junit.Before;
import org.junit.Test;
@@ -48,13 +47,13 @@
DozeServiceFake mServiceFake;
DozeScreenState mScreen;
- private ImmediateHandler mHandler;
+ FakeHandler mHandlerFake;
@Before
public void setUp() throws Exception {
mServiceFake = new DozeServiceFake();
- mHandler = spy(new ImmediateHandler(Looper.getMainLooper()));
- mScreen = new DozeScreenState(mServiceFake, mHandler);
+ mHandlerFake = new FakeHandler(Looper.getMainLooper());
+ mScreen = new DozeScreenState(mServiceFake, mHandlerFake);
}
@Test
@@ -105,27 +104,34 @@
}
@Test
- public void test_postedToHandler() {
+ public void test_initialScreenStatePostedToHandler() {
+ mHandlerFake.setMode(QUEUEING);
+
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
+ mServiceFake.screenStateSet = false;
mScreen.transitionTo(INITIALIZED, DOZE_AOD);
- verify(mHandler).sendMessageAtTime(any(), anyLong());
+ assertFalse(mServiceFake.screenStateSet);
+
+ mHandlerFake.dispatchQueuedMessages();
+
+ assertTrue(mServiceFake.screenStateSet);
+ assertEquals(Display.STATE_DOZE_SUSPEND, mServiceFake.screenState);
}
- private static class ImmediateHandler extends Handler {
+ @Test
+ public void test_noScreenStateSetAfterFinish() {
+ mHandlerFake.setMode(QUEUEING);
- public ImmediateHandler(Looper looper) {
- super(looper);
- }
+ mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
+ mScreen.transitionTo(INITIALIZED, DOZE_AOD);
+ mScreen.transitionTo(DOZE_AOD, FINISH);
- @Override
- public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
- Runnable callback = msg.getCallback();
- if (callback != null) {
- callback.run();
- return false;
- }
- return super.sendMessageAtTime(msg, uptimeMillis);
- }
+ mServiceFake.screenStateSet = false;
+
+ mHandlerFake.dispatchQueuedMessages();
+
+ assertFalse(mServiceFake.screenStateSet);
}
+
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeServiceFake.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeServiceFake.java
index 34026b0..75f97a2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeServiceFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeServiceFake.java
@@ -19,10 +19,16 @@
import android.os.PowerManager;
import android.view.Display;
+/**
+ * Fake implementation of {@link DozeMachine.Service} for tests.
+ *
+ * Useful instead of mocking because it allows verifying state instead of interactions.
+ */
public class DozeServiceFake implements DozeMachine.Service {
public boolean finished;
public int screenState;
+ public boolean screenStateSet;
public boolean requestedWakeup;
public int screenBrightness;
@@ -38,6 +44,7 @@
@Override
public void setDozeScreenState(int state) {
screenState = state;
+ screenStateSet = true;
}
@Override
@@ -53,6 +60,8 @@
public void reset() {
finished = false;
screenState = Display.STATE_UNKNOWN;
+ screenStateSet = false;
+ requestedWakeup = false;
screenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/os/FakeHandler.java b/packages/SystemUI/tests/src/com/android/systemui/utils/os/FakeHandler.java
new file mode 100644
index 0000000..5a7d4b5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/os/FakeHandler.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.utils.os;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
+import java.util.ArrayList;
+
+/**
+ * A handler that allows control over when to dispatch messages and callbacks.
+ *
+ * WARNING: Because most Handler methods are final, the only thing this handler can intercept
+ * are sending messages and posting runnables, but *NOT* removing messages nor runnables.
+ * It also *CANNOT* intercept messages posted to the front of queue.
+ */
+public class FakeHandler extends Handler {
+
+ private Mode mMode = Mode.IMMEDIATE;
+ private ArrayList<Message> mQueuedMessages = new ArrayList<>();
+
+ public FakeHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
+ mQueuedMessages.add(msg);
+ if (mMode == Mode.IMMEDIATE) {
+ dispatchQueuedMessages();
+ }
+ return true;
+ }
+
+ public void setMode(Mode mode) {
+ mMode = mode;
+ }
+
+ /**
+ * Dispatch any messages that have been queued on the calling thread.
+ */
+ public void dispatchQueuedMessages() {
+ ArrayList<Message> messages = new ArrayList<>(mQueuedMessages);
+ mQueuedMessages.clear();
+ for (Message msg : messages) {
+ dispatchMessage(msg);
+ }
+ }
+
+ public enum Mode {
+ /** Messages are dispatched immediately on the calling thread. */
+ IMMEDIATE,
+ /** Messages are queued until {@link #dispatchQueuedMessages()} is called. */
+ QUEUEING,
+ }
+}