diff options
4 files changed, 103 insertions, 1 deletions
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java index dedac5596817..e47a8b7a578c 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java @@ -376,6 +376,11 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS } } + @Nullable + View getAodNotifIconContainer() { + return mAodIconContainer; + } + @Override protected void onViewDetached() { mClockRegistry.unregisterClockChangeListener(mClockChangedListener); @@ -629,6 +634,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS } } else { mNotificationIconAreaController.setupAodIcons(nic); + mAodIconContainer = nic; } } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java index 87d937bc45fb..4fbf077a8852 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java @@ -84,6 +84,7 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV Dumpable { private static final boolean DEBUG = KeyguardConstants.DEBUG; @VisibleForTesting static final String TAG = "KeyguardStatusViewController"; + private static final long STATUS_AREA_HEIGHT_ANIMATION_MILLIS = 133; /** * Duration to use for the animator when the keyguard status view alignment changes, and a @@ -104,6 +105,10 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV private final KeyguardInteractor mKeyguardInteractor; private final PowerInteractor mPowerInteractor; private final KeyguardTransitionInteractor mKeyguardTransitionInteractor; + private final DozeParameters mDozeParameters; + + private View mStatusArea = null; + private ValueAnimator mStatusAreaHeightAnimator = null; private Boolean mSplitShadeEnabled = false; private Boolean mStatusViewCentered = true; @@ -123,6 +128,46 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV } }; + private final View.OnLayoutChangeListener mStatusAreaLayoutChangeListener = + new View.OnLayoutChangeListener() { + @Override + public void onLayoutChange(View v, + int left, int top, int right, int bottom, + int oldLeft, int oldTop, int oldRight, int oldBottom + ) { + if (!mDozeParameters.getAlwaysOn()) { + return; + } + + int oldHeight = oldBottom - oldTop; + int diff = v.getHeight() - oldHeight; + if (diff == 0) { + return; + } + + int startValue = -1 * diff; + long duration = STATUS_AREA_HEIGHT_ANIMATION_MILLIS; + if (mStatusAreaHeightAnimator != null + && mStatusAreaHeightAnimator.isRunning()) { + duration += mStatusAreaHeightAnimator.getDuration() + - mStatusAreaHeightAnimator.getCurrentPlayTime(); + startValue += (int) mStatusAreaHeightAnimator.getAnimatedValue(); + mStatusAreaHeightAnimator.cancel(); + mStatusAreaHeightAnimator = null; + } + + mStatusAreaHeightAnimator = ValueAnimator.ofInt(startValue, 0); + mStatusAreaHeightAnimator.setDuration(duration); + final View nic = mKeyguardClockSwitchController.getAodNotifIconContainer(); + if (nic != null) { + mStatusAreaHeightAnimator.addUpdateListener(anim -> { + nic.setTranslationY((int) anim.getAnimatedValue()); + }); + } + mStatusAreaHeightAnimator.start(); + } + }; + @Inject public KeyguardStatusViewController( KeyguardStatusView keyguardStatusView, @@ -144,6 +189,7 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV mKeyguardClockSwitchController = keyguardClockSwitchController; mKeyguardUpdateMonitor = keyguardUpdateMonitor; mConfigurationController = configurationController; + mDozeParameters = dozeParameters; mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, keyguardStateController, dozeParameters, screenOffAnimationController, /* animateYPos= */ true, logger.getBuffer()); @@ -218,12 +264,15 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV @Override protected void onViewAttached() { + mStatusArea = mView.findViewById(R.id.keyguard_status_area); + mStatusArea.addOnLayoutChangeListener(mStatusAreaLayoutChangeListener); mKeyguardUpdateMonitor.registerCallback(mInfoCallback); mConfigurationController.addCallback(mConfigurationListener); } @Override protected void onViewDetached() { + mStatusArea.removeOnLayoutChangeListener(mStatusAreaLayoutChangeListener); mKeyguardUpdateMonitor.removeCallback(mInfoCallback); mConfigurationController.removeCallback(mConfigurationListener); } @@ -293,9 +342,15 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV /** * Get the height of the keyguard status view without the notification icon area, as that's * only visible on AOD. + * + * We internally animate height changes to the status area to prevent discontinuities in the + * doze animation introduced by the height suddenly changing due to smartpace. */ public int getLockscreenHeight() { - return mView.getHeight() - mKeyguardClockSwitchController.getNotificationIconAreaHeight(); + int heightAnimValue = mStatusAreaHeightAnimator == null ? 0 : + (int) mStatusAreaHeightAnimator.getAnimatedValue(); + return mView.getHeight() + heightAnimValue + - mKeyguardClockSwitchController.getNotificationIconAreaHeight(); } /** diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java index 146715d26b7d..13fb42ce8c3e 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java @@ -35,6 +35,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; import com.android.systemui.power.data.repository.FakePowerRepository; import com.android.systemui.power.domain.interactor.PowerInteractorFactory; +import com.android.systemui.res.R; import com.android.systemui.statusbar.notification.AnimatableProperty; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.ScreenOffAnimationController; @@ -70,6 +71,7 @@ public class KeyguardStatusViewControllerBaseTest extends SysuiTestCase { @Mock protected KeyguardClockSwitch mKeyguardClockSwitch; @Mock protected FrameLayout mMediaHostContainer; + @Mock protected KeyguardStatusAreaView mKeyguardStatusAreaView; @Before public void setup() { @@ -109,6 +111,8 @@ public class KeyguardStatusViewControllerBaseTest extends SysuiTestCase { when(mKeyguardStatusView.getViewTreeObserver()).thenReturn(mViewTreeObserver); when(mKeyguardClockSwitchController.getView()).thenReturn(mKeyguardClockSwitch); when(mKeyguardTransitionInteractor.getGoneToAodTransition()).thenReturn(emptyFlow()); + when(mKeyguardStatusView.findViewById(R.id.keyguard_status_area)) + .thenReturn(mKeyguardStatusAreaView); } protected void givenViewAttached() { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java index 948942fbce3a..9c3288b9f93d 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java @@ -16,6 +16,8 @@ package com.android.keyguard; +import static junit.framework.Assert.assertEquals; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyLong; @@ -27,6 +29,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.animation.AnimatorTestRule; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -40,6 +43,7 @@ import com.android.systemui.res.R; import com.android.systemui.statusbar.notification.AnimatableProperty; import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -51,6 +55,9 @@ import java.lang.reflect.Field; @RunWith(AndroidTestingRunner.class) public class KeyguardStatusViewControllerTest extends KeyguardStatusViewControllerBaseTest { + @Rule + public final AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule(); + @Test public void dozeTimeTick_updatesSlice() { mController.dozeTimeTick(); @@ -230,4 +237,34 @@ public class KeyguardStatusViewControllerTest extends KeyguardStatusViewControll throw new RuntimeException(e); } } + + @Test + public void statusAreaHeightChange_animatesHeightOutputChange() { + // Init & Capture Layout Listener + mController.onInit(); + mController.onViewAttached(); + + when(mDozeParameters.getAlwaysOn()).thenReturn(true); + ArgumentCaptor<View.OnLayoutChangeListener> captor = + ArgumentCaptor.forClass(View.OnLayoutChangeListener.class); + verify(mKeyguardStatusAreaView).addOnLayoutChangeListener(captor.capture()); + View.OnLayoutChangeListener listener = captor.getValue(); + + // Setup and validate initial height + when(mKeyguardStatusView.getHeight()).thenReturn(200); + when(mKeyguardClockSwitchController.getNotificationIconAreaHeight()).thenReturn(10); + assertEquals(190, mController.getLockscreenHeight()); + + // Trigger Change and validate value unchanged immediately + when(mKeyguardStatusAreaView.getHeight()).thenReturn(100); + when(mKeyguardStatusView.getHeight()).thenReturn(300); // Include child height + listener.onLayoutChange(mKeyguardStatusAreaView, + /* new layout */ 100, 300, 200, 400, + /* old layout */ 100, 300, 200, 300); + assertEquals(190, mController.getLockscreenHeight()); + + // Complete animation, validate height increased + mAnimatorTestRule.advanceTimeBy(200); + assertEquals(290, mController.getLockscreenHeight()); + } } |