Skip to content

Commit

Permalink
Merge "Smooth discontinuous height changes to KeyguardStatusViewContr…
Browse files Browse the repository at this point in the history
…oller" into main
  • Loading branch information
Hawkwood Glazier authored and Android (Google) Code Review committed Nov 21, 2023
2 parents e3c62a0 + dd15619 commit a8bb7bf
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,11 @@ int getNotificationIconAreaHeight() {
}
}

@Nullable
View getAodNotifIconContainer() {
return mAodIconContainer;
}

@Override
protected void onViewDetached() {
mClockRegistry.unregisterClockChangeListener(mClockChangedListener);
Expand Down Expand Up @@ -639,6 +644,7 @@ private void updateAodIcons() {
}
} else {
mNotificationIconAreaController.setupAodIcons(nic);
mAodIconContainer = nic;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
Expand All @@ -123,6 +128,46 @@ public void onTransitionEnd(Transition transition) {
}
};

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,
Expand All @@ -144,6 +189,7 @@ public KeyguardStatusViewController(
mKeyguardClockSwitchController = keyguardClockSwitchController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mConfigurationController = configurationController;
mDozeParameters = dozeParameters;
mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, keyguardStateController,
dozeParameters, screenOffAnimationController, /* animateYPos= */ true,
logger.getBuffer());
Expand Down Expand Up @@ -218,12 +264,15 @@ public KeyguardStatusView getView() {

@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);
}
Expand Down Expand Up @@ -293,9 +342,15 @@ public void updatePivot(float parentWidth, float parentHeight) {
/**
* 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();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
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;
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -109,6 +111,8 @@ void setProperty(
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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -27,6 +29,7 @@
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;
Expand All @@ -40,6 +43,7 @@
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;
Expand All @@ -51,6 +55,9 @@
@RunWith(AndroidTestingRunner.class)
public class KeyguardStatusViewControllerTest extends KeyguardStatusViewControllerBaseTest {

@Rule
public final AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule();

@Test
public void dozeTimeTick_updatesSlice() {
mController.dozeTimeTick();
Expand Down Expand Up @@ -230,4 +237,34 @@ private void setCompanion(ViewHierarchyAnimator.Companion companion) {
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());
}
}

0 comments on commit a8bb7bf

Please sign in to comment.