Merge "Fix Clear all Notifications Animation to avoid QS Panel Flicking" into tm-qpr-dev am: ac8c6ac9ea
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20105405 Change-Id: I6650c7a1573afc6be8c9c08b2cf12a544ea72fe5 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -2093,7 +2093,8 @@ public final class NotificationPanelViewController {
|
|||||||
animator.start();
|
animator.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onFlingEnd(boolean cancelled) {
|
@VisibleForTesting
|
||||||
|
void onFlingEnd(boolean cancelled) {
|
||||||
mIsFlinging = false;
|
mIsFlinging = false;
|
||||||
// No overshoot when the animation ends
|
// No overshoot when the animation ends
|
||||||
setOverExpansionInternal(0, false /* isFromGesture */);
|
setOverExpansionInternal(0, false /* isFromGesture */);
|
||||||
@@ -3834,12 +3835,14 @@ public final class NotificationPanelViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setIsClosing(boolean isClosing) {
|
@VisibleForTesting
|
||||||
|
void setIsClosing(boolean isClosing) {
|
||||||
boolean wasClosing = isClosing();
|
boolean wasClosing = isClosing();
|
||||||
mClosing = isClosing;
|
mClosing = isClosing;
|
||||||
if (wasClosing != isClosing) {
|
if (wasClosing != isClosing) {
|
||||||
mPanelEventsEmitter.notifyPanelCollapsingChanged(isClosing);
|
mPanelEventsEmitter.notifyPanelCollapsingChanged(isClosing);
|
||||||
}
|
}
|
||||||
|
mAmbientState.setIsClosing(isClosing);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateDozingVisibilities(boolean animate) {
|
private void updateDozingVisibilities(boolean animate) {
|
||||||
@@ -4630,14 +4633,16 @@ public final class NotificationPanelViewController {
|
|||||||
Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
|
Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyExpandingStarted() {
|
@VisibleForTesting
|
||||||
|
void notifyExpandingStarted() {
|
||||||
if (!mExpanding) {
|
if (!mExpanding) {
|
||||||
mExpanding = true;
|
mExpanding = true;
|
||||||
onExpandingStarted();
|
onExpandingStarted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyExpandingFinished() {
|
@VisibleForTesting
|
||||||
|
void notifyExpandingFinished() {
|
||||||
endClosing();
|
endClosing();
|
||||||
if (mExpanding) {
|
if (mExpanding) {
|
||||||
mExpanding = false;
|
mExpanding = false;
|
||||||
|
|||||||
@@ -142,6 +142,11 @@ public class AmbientState implements Dumpable {
|
|||||||
*/
|
*/
|
||||||
private boolean mIsFlingRequiredAfterLockScreenSwipeUp = false;
|
private boolean mIsFlingRequiredAfterLockScreenSwipeUp = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the shade is currently closing.
|
||||||
|
*/
|
||||||
|
private boolean mIsClosing;
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public boolean isFlingRequiredAfterLockScreenSwipeUp() {
|
public boolean isFlingRequiredAfterLockScreenSwipeUp() {
|
||||||
return mIsFlingRequiredAfterLockScreenSwipeUp;
|
return mIsFlingRequiredAfterLockScreenSwipeUp;
|
||||||
@@ -717,6 +722,20 @@ public class AmbientState implements Dumpable {
|
|||||||
&& mStatusBarKeyguardViewManager.isBouncerInTransit();
|
&& mStatusBarKeyguardViewManager.isBouncerInTransit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param isClosing Whether the shade is currently closing.
|
||||||
|
*/
|
||||||
|
public void setIsClosing(boolean isClosing) {
|
||||||
|
mIsClosing = isClosing;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Whether the shade is currently closing.
|
||||||
|
*/
|
||||||
|
public boolean isClosing() {
|
||||||
|
return mIsClosing;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dump(PrintWriter pw, String[] args) {
|
public void dump(PrintWriter pw, String[] args) {
|
||||||
pw.println("mTopPadding=" + mTopPadding);
|
pw.println("mTopPadding=" + mTopPadding);
|
||||||
@@ -761,5 +780,6 @@ public class AmbientState implements Dumpable {
|
|||||||
+ mIsFlingRequiredAfterLockScreenSwipeUp);
|
+ mIsFlingRequiredAfterLockScreenSwipeUp);
|
||||||
pw.println("mZDistanceBetweenElements=" + mZDistanceBetweenElements);
|
pw.println("mZDistanceBetweenElements=" + mZDistanceBetweenElements);
|
||||||
pw.println("mBaseZHeight=" + mBaseZHeight);
|
pw.println("mBaseZHeight=" + mBaseZHeight);
|
||||||
|
pw.println("mIsClosing=" + mIsClosing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -255,7 +255,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
private boolean mClearAllInProgress;
|
private boolean mClearAllInProgress;
|
||||||
private FooterClearAllListener mFooterClearAllListener;
|
private FooterClearAllListener mFooterClearAllListener;
|
||||||
private boolean mFlingAfterUpEvent;
|
private boolean mFlingAfterUpEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Was the scroller scrolled to the top when the down motion was observed?
|
* Was the scroller scrolled to the top when the down motion was observed?
|
||||||
*/
|
*/
|
||||||
@@ -4020,8 +4019,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
setOwnScrollY(0);
|
setOwnScrollY(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
|
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
|
||||||
private void setIsExpanded(boolean isExpanded) {
|
void setIsExpanded(boolean isExpanded) {
|
||||||
boolean changed = isExpanded != mIsExpanded;
|
boolean changed = isExpanded != mIsExpanded;
|
||||||
mIsExpanded = isExpanded;
|
mIsExpanded = isExpanded;
|
||||||
mStackScrollAlgorithm.setIsExpanded(isExpanded);
|
mStackScrollAlgorithm.setIsExpanded(isExpanded);
|
||||||
@@ -4842,13 +4842,21 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
|
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
|
||||||
private void setOwnScrollY(int ownScrollY) {
|
void setOwnScrollY(int ownScrollY) {
|
||||||
setOwnScrollY(ownScrollY, false /* animateScrollChangeListener */);
|
setOwnScrollY(ownScrollY, false /* animateScrollChangeListener */);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
|
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
|
||||||
private void setOwnScrollY(int ownScrollY, boolean animateStackYChangeListener) {
|
private void setOwnScrollY(int ownScrollY, boolean animateStackYChangeListener) {
|
||||||
|
// Avoid Flicking during clear all
|
||||||
|
// when the shade finishes closing, onExpansionStopped will call
|
||||||
|
// resetScrollPosition to setOwnScrollY to 0
|
||||||
|
if (mAmbientState.isClosing()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (ownScrollY != mOwnScrollY) {
|
if (ownScrollY != mOwnScrollY) {
|
||||||
// We still want to call the normal scrolled changed for accessibility reasons
|
// We still want to call the normal scrolled changed for accessibility reasons
|
||||||
onScrollChanged(mScrollX, ownScrollY, mScrollX, mOwnScrollY);
|
onScrollChanged(mScrollX, ownScrollY, mScrollX, mOwnScrollY);
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import static org.mockito.Mockito.atLeast;
|
|||||||
import static org.mockito.Mockito.atLeastOnce;
|
import static org.mockito.Mockito.atLeastOnce;
|
||||||
import static org.mockito.Mockito.clearInvocations;
|
import static org.mockito.Mockito.clearInvocations;
|
||||||
import static org.mockito.Mockito.doAnswer;
|
import static org.mockito.Mockito.doAnswer;
|
||||||
|
import static org.mockito.Mockito.inOrder;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
@@ -173,6 +174,7 @@ import org.junit.Before;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.InOrder;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
import org.mockito.stubbing.Answer;
|
import org.mockito.stubbing.Answer;
|
||||||
@@ -1540,6 +1542,33 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When shade is flinging to close and this fling is not intercepted,
|
||||||
|
* {@link AmbientState#setIsClosing(boolean)} should be called before
|
||||||
|
* {@link NotificationStackScrollLayoutController#onExpansionStopped()}
|
||||||
|
* to ensure scrollY can be correctly set to be 0
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void onShadeFlingClosingEnd_mAmbientStateSetClose_thenOnExpansionStopped() {
|
||||||
|
// Given: Shade is expanded
|
||||||
|
mNotificationPanelViewController.notifyExpandingFinished();
|
||||||
|
mNotificationPanelViewController.setIsClosing(false);
|
||||||
|
|
||||||
|
// When: Shade flings to close not canceled
|
||||||
|
mNotificationPanelViewController.notifyExpandingStarted();
|
||||||
|
mNotificationPanelViewController.setIsClosing(true);
|
||||||
|
mNotificationPanelViewController.onFlingEnd(false);
|
||||||
|
|
||||||
|
// Then: AmbientState's mIsClosing should be set to false
|
||||||
|
// before mNotificationStackScrollLayoutController.onExpansionStopped() is called
|
||||||
|
// to ensure NotificationStackScrollLayout.resetScrollPosition() -> resetScrollPosition
|
||||||
|
// -> setOwnScrollY(0) can set scrollY to 0 when shade is closed
|
||||||
|
InOrder inOrder = inOrder(mAmbientState, mNotificationStackScrollLayoutController);
|
||||||
|
inOrder.verify(mAmbientState).setIsClosing(false);
|
||||||
|
inOrder.verify(mNotificationStackScrollLayoutController).onExpansionStopped();
|
||||||
|
}
|
||||||
|
|
||||||
private static MotionEvent createMotionEvent(int x, int y, int action) {
|
private static MotionEvent createMotionEvent(int x, int y, int action) {
|
||||||
return MotionEvent.obtain(
|
return MotionEvent.obtain(
|
||||||
/* downTime= */ 0, /* eventTime= */ 0, action, x, y, /* metaState= */ 0);
|
/* downTime= */ 0, /* eventTime= */ 0, action, x, y, /* metaState= */ 0);
|
||||||
|
|||||||
@@ -361,6 +361,22 @@ class AmbientStateTest : SysuiTestCase() {
|
|||||||
assertThat(sut.isOnKeyguard).isFalse()
|
assertThat(sut.isOnKeyguard).isFalse()
|
||||||
}
|
}
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
|
// region mIsClosing
|
||||||
|
@Test
|
||||||
|
fun isClosing_whenShadeClosing_shouldReturnTrue() {
|
||||||
|
sut.setIsClosing(true)
|
||||||
|
|
||||||
|
assertThat(sut.isClosing).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun isClosing_whenShadeFinishClosing_shouldReturnFalse() {
|
||||||
|
sut.setIsClosing(false)
|
||||||
|
|
||||||
|
assertThat(sut.isClosing).isFalse()
|
||||||
|
}
|
||||||
|
// endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
// region Arrange helper methods.
|
// region Arrange helper methods.
|
||||||
|
|||||||
@@ -728,6 +728,57 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
|
|||||||
verify(mNotificationStackSizeCalculator).computeHeight(any(), anyInt(), anyFloat());
|
verify(mNotificationStackSizeCalculator).computeHeight(any(), anyInt(), anyFloat());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetOwnScrollY_shadeNotClosing_scrollYChanges() {
|
||||||
|
// Given: shade is not closing, scrollY is 0
|
||||||
|
mAmbientState.setScrollY(0);
|
||||||
|
assertEquals(0, mAmbientState.getScrollY());
|
||||||
|
mAmbientState.setIsClosing(false);
|
||||||
|
|
||||||
|
// When: call NotificationStackScrollLayout.setOwnScrollY to set scrollY to 1
|
||||||
|
mStackScroller.setOwnScrollY(1);
|
||||||
|
|
||||||
|
// Then: scrollY should be set to 1
|
||||||
|
assertEquals(1, mAmbientState.getScrollY());
|
||||||
|
|
||||||
|
// Reset scrollY back to 0 to avoid interfering with other tests
|
||||||
|
mStackScroller.setOwnScrollY(0);
|
||||||
|
assertEquals(0, mAmbientState.getScrollY());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetOwnScrollY_shadeClosing_scrollYDoesNotChange() {
|
||||||
|
// Given: shade is closing, scrollY is 0
|
||||||
|
mAmbientState.setScrollY(0);
|
||||||
|
assertEquals(0, mAmbientState.getScrollY());
|
||||||
|
mAmbientState.setIsClosing(true);
|
||||||
|
|
||||||
|
// When: call NotificationStackScrollLayout.setOwnScrollY to set scrollY to 1
|
||||||
|
mStackScroller.setOwnScrollY(1);
|
||||||
|
|
||||||
|
// Then: scrollY should not change, it should still be 0
|
||||||
|
assertEquals(0, mAmbientState.getScrollY());
|
||||||
|
|
||||||
|
// Reset scrollY and mAmbientState.mIsClosing to avoid interfering with other tests
|
||||||
|
mAmbientState.setIsClosing(false);
|
||||||
|
mStackScroller.setOwnScrollY(0);
|
||||||
|
assertEquals(0, mAmbientState.getScrollY());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onShadeFlingClosingEnd_scrollYShouldBeSetToZero() {
|
||||||
|
// Given: mAmbientState.mIsClosing is set to be true
|
||||||
|
// mIsExpanded is set to be false
|
||||||
|
mAmbientState.setIsClosing(true);
|
||||||
|
mStackScroller.setIsExpanded(false);
|
||||||
|
|
||||||
|
// When: onExpansionStopped is called
|
||||||
|
mStackScroller.onExpansionStopped();
|
||||||
|
|
||||||
|
// Then: mAmbientState.scrollY should be set to be 0
|
||||||
|
assertEquals(mAmbientState.getScrollY(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
private void setBarStateForTest(int state) {
|
private void setBarStateForTest(int state) {
|
||||||
// Can't inject this through the listener or we end up on the actual implementation
|
// Can't inject this through the listener or we end up on the actual implementation
|
||||||
// rather than the mock because the spy just coppied the anonymous inner /shruggie.
|
// rather than the mock because the spy just coppied the anonymous inner /shruggie.
|
||||||
|
|||||||
Reference in New Issue
Block a user