Screen off animation
SysUI can now control the screen off animation as long as
config_dozeAfterScreenOff is set to false.
The current implementation collapses the notification shade and moves
the clock whenever the use is on the lock screen, or will fade the
scrims and show the clock when the keyguard is occluded.
Display state change (on, doze, doze_suspended) is delayed to let the
animations occur at 60Hz.
Test: atest packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java
Test: atest packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java
Test: atest packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
Test: atest tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java
Test: atest tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
Test: atest packages/SystemUI/tests/src/com/android/systemui/keyguard/WakefulnessLifecycleTest.java
Fixes: 73178121
Change-Id: Id5d964452f342d4e97bedf1084efa808604e602c
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 8c4fd73..6683636 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
@@ -28,6 +28,9 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.os.Looper;
@@ -37,6 +40,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.util.wakelock.WakeLock;
import com.android.systemui.utils.os.FakeHandler;
import org.junit.Before;
@@ -54,14 +58,17 @@
FakeHandler mHandlerFake;
@Mock
DozeParameters mDozeParameters;
+ @Mock
+ WakeLock mWakeLock;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(true);
+ when(mDozeParameters.getAlwaysOn()).thenReturn(true);
mServiceFake = new DozeServiceFake();
mHandlerFake = new FakeHandler(Looper.getMainLooper());
- mScreen = new DozeScreenState(mServiceFake, mHandlerFake, mDozeParameters);
+ mScreen = new DozeScreenState(mServiceFake, mHandlerFake, mDozeParameters, mWakeLock);
}
@Test
@@ -142,4 +149,23 @@
assertFalse(mServiceFake.screenStateSet);
}
+ @Test
+ public void test_holdsWakeLockWhenGoingToLowPowerDelayed() {
+ // Transition to low power mode will be delayed to let
+ // animations play at 60 fps.
+ when(mDozeParameters.shouldControlScreenOff()).thenReturn(true);
+ mHandlerFake.setMode(QUEUEING);
+
+ mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
+ mHandlerFake.dispatchQueuedMessages();
+ reset(mWakeLock);
+
+ mScreen.transitionTo(INITIALIZED, DOZE_AOD);
+ verify(mWakeLock).acquire();
+ verify(mWakeLock, never()).release();
+
+ mHandlerFake.dispatchQueuedMessages();
+ verify(mWakeLock).release();
+ }
+
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java
index 75ade9d..0d8d952 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java
@@ -28,15 +28,20 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.AlarmManager;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.PowerManager;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.wakelock.WakeLockFake;
@@ -46,33 +51,39 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class DozeUiTest extends SysuiTestCase {
+ @Mock
private AlarmManager mAlarmManager;
+ @Mock
private DozeMachine mMachine;
+ @Mock
+ private DozeParameters mDozeParameters;
+ @Mock
+ private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock
+ private DozeHost mHost;
private WakeLockFake mWakeLock;
- private DozeHostFake mHost;
private Handler mHandler;
private HandlerThread mHandlerThread;
private DozeUi mDozeUi;
@Before
public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
mHandlerThread = new HandlerThread("DozeUiTest");
mHandlerThread.start();
- mAlarmManager = mock(AlarmManager.class);
- mMachine = mock(DozeMachine.class);
mWakeLock = new WakeLockFake();
- mHost = new DozeHostFake();
mHandler = mHandlerThread.getThreadHandler();
- DozeParameters params = mock(DozeParameters.class);
- when(params.getCanControlScreenOffAnimation()).thenReturn(true);
- when(params.getDisplayNeedsBlanking()).thenReturn(false);
- mDozeUi = new DozeUi(mContext, mAlarmManager, mMachine, mWakeLock, mHost, mHandler, params);
+ mDozeUi = new DozeUi(mContext, mAlarmManager, mMachine, mWakeLock, mHost, mHandler,
+ mDozeParameters, mKeyguardUpdateMonitor);
}
@After
@@ -96,18 +107,69 @@
}
@Test
- public void propagatesAnimateScreenOff() {
- Assert.assertTrue("animateScreenOff should be true", mHost.animateScreenOff);
+ public void propagatesAnimateScreenOff_noAlwaysOn() {
+ reset(mHost);
+ when(mDozeParameters.getAlwaysOn()).thenReturn(false);
+ when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(false);
- DozeParameters params = mock(DozeParameters.class);
- new DozeUi(mContext, mAlarmManager, mMachine, mWakeLock, mHost, mHandler, params);
- Assert.assertFalse("animateScreenOff should be false", mHost.animateScreenOff);
+ mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(false);
+ verify(mHost).setAnimateScreenOff(eq(false));
}
@Test
- public void transitionSetsAnimateWakeup() {
- mHost.animateWakeup = false;
+ public void propagatesAnimateScreenOff_alwaysOn() {
+ reset(mHost);
+ when(mDozeParameters.getAlwaysOn()).thenReturn(true);
+ when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(false);
+
+ // Take over when the keyguard is visible.
+ mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(true);
+ verify(mHost).setAnimateScreenOff(eq(true));
+
+ // Do not animate screen-off when keyguard isn't visible - PowerManager will do it.
+ mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(false);
+ verify(mHost).setAnimateScreenOff(eq(false));
+ }
+
+ @Test
+ public void neverAnimateScreenOff_whenNotSupported() {
+ // Re-initialize DozeParameters saying that the display requires blanking.
+ reset(mDozeParameters);
+ reset(mHost);
+ when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(true);
+ mDozeUi = new DozeUi(mContext, mAlarmManager, mMachine, mWakeLock, mHost, mHandler,
+ mDozeParameters, mKeyguardUpdateMonitor);
+
+ // Never animate if display doesn't support it.
+ mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(true);
+ mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(false);
+ verify(mHost, never()).setAnimateScreenOff(eq(false));
+ }
+
+ @Test
+ public void transitionSetsAnimateWakeup_alwaysOn() {
+ when(mDozeParameters.getAlwaysOn()).thenReturn(true);
+ when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(false);
mDozeUi.transitionTo(UNINITIALIZED, DOZE);
- Assert.assertTrue("animateScreenOff should be true", mHost.animateWakeup);
+ verify(mHost).setAnimateWakeup(eq(true));
+ }
+
+ @Test
+ public void keyguardVisibility_changesControlScreenOffAnimation() {
+ // Pre-condition
+ reset(mDozeParameters);
+ when(mDozeParameters.getAlwaysOn()).thenReturn(true);
+ when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(false);
+
+ mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(false);
+ verify(mDozeParameters).setControlScreenOffAnimation(eq(false));
+ mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(true);
+ verify(mDozeParameters).setControlScreenOffAnimation(eq(true));
+ }
+
+ @Test
+ public void transitionSetsAnimateWakeup_noAlwaysOn() {
+ mDozeUi.transitionTo(UNINITIALIZED, DOZE);
+ verify(mHost).setAnimateWakeup(eq(false));
}
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java
index 2705bca..5c80bb5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java
@@ -24,7 +24,6 @@
import static org.mockito.Mockito.when;
import android.app.IWallpaperManager;
-import android.os.Handler;
import android.os.RemoteException;
import android.support.test.filters.SmallTest;
@@ -37,7 +36,6 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Mock;
-import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
@RunWith(JUnit4.class)
@@ -77,7 +75,7 @@
public void testAnimates_whenSupported() throws RemoteException {
// Pre-conditions
when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(false);
- when(mDozeParameters.getCanControlScreenOffAnimation()).thenReturn(true);
+ when(mDozeParameters.shouldControlScreenOff()).thenReturn(true);
when(mDozeParameters.getAlwaysOn()).thenReturn(true);
mDozeWallpaperState.transitionTo(DozeMachine.State.UNINITIALIZED,
@@ -92,8 +90,8 @@
public void testDoesNotAnimate_whenNotSupported() throws RemoteException {
// Pre-conditions
when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(true);
- when(mDozeParameters.getCanControlScreenOffAnimation()).thenReturn(false);
when(mDozeParameters.getAlwaysOn()).thenReturn(true);
+ when(mDozeParameters.shouldControlScreenOff()).thenReturn(false);
mDozeWallpaperState.transitionTo(DozeMachine.State.UNINITIALIZED,
DozeMachine.State.DOZE_AOD);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WakefulnessLifecycleTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WakefulnessLifecycleTest.java
index e15e0b4..9eba9b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WakefulnessLifecycleTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WakefulnessLifecycleTest.java
@@ -18,6 +18,7 @@
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -99,6 +100,23 @@
}
@Test
+ public void doesNotDispatchTwice() throws Exception {
+ mWakefulness.dispatchStartedWakingUp();
+ mWakefulness.dispatchStartedWakingUp();
+ mWakefulness.dispatchFinishedWakingUp();
+ mWakefulness.dispatchFinishedWakingUp();
+ mWakefulness.dispatchStartedGoingToSleep();
+ mWakefulness.dispatchStartedGoingToSleep();
+ mWakefulness.dispatchFinishedGoingToSleep();
+ mWakefulness.dispatchFinishedGoingToSleep();
+
+ verify(mWakefulnessObserver, times(1)).onStartedGoingToSleep();
+ verify(mWakefulnessObserver, times(1)).onFinishedGoingToSleep();
+ verify(mWakefulnessObserver, times(1)).onStartedWakingUp();
+ verify(mWakefulnessObserver, times(1)).onFinishedWakingUp();
+ }
+
+ @Test
public void dump() throws Exception {
mWakefulness.dump(null, new PrintWriter(new ByteArrayOutputStream()), new String[0]);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
index e89ff97..550a35d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
@@ -16,11 +16,15 @@
package com.android.systemui.statusbar.phone;
+import android.content.Context;
+import android.os.PowerManager;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.phone.DozeParameters.IntInOutMatcher;
+
+import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -28,6 +32,14 @@
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class DozeParametersTest extends SysuiTestCase {
@@ -186,4 +198,38 @@
}
}
+ @Test
+ public void test_setControlScreenOffAnimation_setsDozeAfterScreenOff_false() {
+ TestableDozeParameters dozeParameters = new TestableDozeParameters(getContext());
+ PowerManager mockedPowerManager = dozeParameters.getPowerManager();
+ dozeParameters.setControlScreenOffAnimation(true);
+ reset(mockedPowerManager);
+ dozeParameters.setControlScreenOffAnimation(false);
+ verify(mockedPowerManager).setDozeAfterScreenOff(eq(true));
+ }
+
+ @Test
+ public void test_setControlScreenOffAnimation_setsDozeAfterScreenOff_true() {
+ TestableDozeParameters dozeParameters = new TestableDozeParameters(getContext());
+ PowerManager mockedPowerManager = dozeParameters.getPowerManager();
+ dozeParameters.setControlScreenOffAnimation(false);
+ reset(mockedPowerManager);
+ dozeParameters.setControlScreenOffAnimation(true);
+ verify(dozeParameters.getPowerManager()).setDozeAfterScreenOff(eq(false));
+ }
+
+ private class TestableDozeParameters extends DozeParameters {
+ private PowerManager mPowerManager;
+
+ TestableDozeParameters(Context context) {
+ super(context);
+ mPowerManager = mock(PowerManager.class);
+ }
+
+ @Override
+ protected PowerManager getPowerManager() {
+ return mPowerManager;
+ }
+ }
+
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java
index ca2f713..203ebe6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java
@@ -34,18 +34,23 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
public class DozeScrimControllerTest extends SysuiTestCase {
+ @Mock
private ScrimController mScrimController;
+ @Mock
+ private DozeParameters mDozeParameters;
private DozeScrimController mDozeScrimController;
@Before
public void setup() {
- mScrimController = mock(ScrimController.class);
+ MockitoAnnotations.initMocks(this);
// Make sure callbacks will be invoked to complete the lifecycle.
doAnswer(invocationOnMock -> {
ScrimController.Callback callback = invocationOnMock.getArgument(1);
@@ -56,7 +61,8 @@
}).when(mScrimController).transitionTo(any(ScrimState.class),
any(ScrimController.Callback.class));
- mDozeScrimController = new DozeScrimController(mScrimController, getContext());
+ mDozeScrimController = new DozeScrimController(mScrimController, getContext(),
+ mDozeParameters);
mDozeScrimController.setDozing(true);
}
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 d32c9a8..22e4980 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
@@ -349,7 +349,7 @@
}
@Test
- public void testWillHideAoDWallpaper() {
+ public void testWillHideAodWallpaper() {
mScrimController.setWallpaperSupportsAmbientMode(true);
mScrimController.transitionTo(ScrimState.AOD);
verify(mAlarmManager).setExact(anyInt(), anyLong(), any(), any(), any());
@@ -540,6 +540,7 @@
private FakeHandler mHandler;
private boolean mAnimationCancelled;
+ boolean mOnPreDrawCalled;
SynchronousScrimController(LightBarController lightBarController,
ScrimView scrimBehind, ScrimView scrimInFront, View headsUpScrim,
@@ -550,6 +551,12 @@
mHandler = new FakeHandler(Looper.myLooper());
}
+ @Override
+ public boolean onPreDraw() {
+ mOnPreDrawCalled = true;
+ return super.onPreDraw();
+ }
+
void finishAnimationsImmediately() {
boolean[] animationFinished = {false};
setOnAnimationFinished(()-> animationFinished[0] = true);