Fix headsup notification RemoteInputView appearance animation
This CL fixes a bug where the appearance animation of the RemoteInputView in a headsup collapsed notification was slightly broken. The RemoteInputView would do its appearance animation partly outside (below) the notification boundaries. This was because the RemoteInputView was prevented to overlap the hint during the expand animation.
Bug: 174148361
Test: atest RemoteInputViewTest, Manual, i.e. posting various types of Notifications from the Notify2-RVC application with a reply action added to them. Then observing the animations visually and analyzing frames from screen recordings.
Change-Id: I90a637e9b57dea0e365699cef9e088a562301f55
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index 47cdde4..56eb4b1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.collection.inflation;
+import static com.android.systemui.flags.Flags.NOTIFICATION_INLINE_REPLY_ANIMATION;
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED;
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED;
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC;
@@ -30,6 +31,7 @@
import com.android.internal.util.NotificationMessagingUtil;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -71,6 +73,7 @@
private NotificationListContainer mListContainer;
private BindRowCallback mBindRowCallback;
private NotificationClicker mNotificationClicker;
+ private FeatureFlags mFeatureFlags;
@Inject
public NotificationRowBinderImpl(
@@ -82,7 +85,8 @@
RowContentBindStage rowContentBindStage,
Provider<RowInflaterTask> rowInflaterTaskProvider,
ExpandableNotificationRowComponent.Builder expandableNotificationRowComponentBuilder,
- IconManager iconManager) {
+ IconManager iconManager,
+ FeatureFlags featureFlags) {
mContext = context;
mNotifBindPipeline = notifBindPipeline;
mRowContentBindStage = rowContentBindStage;
@@ -92,6 +96,7 @@
mRowInflaterTaskProvider = rowInflaterTaskProvider;
mExpandableNotificationRowComponentBuilder = expandableNotificationRowComponentBuilder;
mIconManager = iconManager;
+ mFeatureFlags = featureFlags;
}
/**
@@ -176,6 +181,8 @@
entry.setRow(row);
mNotifBindPipeline.manageRow(entry, row);
mBindRowCallback.onBindRow(row);
+ row.setInlineReplyAnimationFlagEnabled(
+ mFeatureFlags.isEnabled(NOTIFICATION_INLINE_REPLY_ANIMATION));
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index c7c1634..c271f09 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -284,6 +284,7 @@
private View.OnClickListener mOnAppClickListener;
private View.OnClickListener mOnFeedbackClickListener;
private Path mExpandingClipPath;
+ private boolean mIsInlineReplyAnimationFlagEnabled = false;
// Listener will be called when receiving a long click event.
// Use #setLongPressPosition to optionally assign positional data with the long press.
@@ -3073,6 +3074,10 @@
return 0;
}
+ public void setInlineReplyAnimationFlagEnabled(boolean isEnabled) {
+ mIsInlineReplyAnimationFlagEnabled = isEnabled;
+ }
+
@Override
public void setActualHeight(int height, boolean notifyListeners) {
boolean changed = height != getActualHeight();
@@ -3092,7 +3097,11 @@
}
int contentHeight = Math.max(getMinHeight(), height);
for (NotificationContentView l : mLayouts) {
- l.setContentHeight(contentHeight);
+ if (mIsInlineReplyAnimationFlagEnabled) {
+ l.setContentHeight(height);
+ } else {
+ l.setContentHeight(contentHeight);
+ }
}
if (mIsSummaryWithChildren) {
mChildrenContainer.setActualHeight(height);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 83d6abb..e46bf52 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -627,6 +627,13 @@
int hint;
if (mHeadsUpChild != null && isVisibleOrTransitioning(VISIBLE_TYPE_HEADSUP)) {
hint = getViewHeight(VISIBLE_TYPE_HEADSUP);
+ if (mHeadsUpRemoteInput != null && mHeadsUpRemoteInput.isAnimatingAppearance()
+ && mHeadsUpRemoteInputController.isFocusAnimationFlagActive()) {
+ // While the RemoteInputView is animating its appearance, it should be allowed
+ // to overlap the hint, therefore no space is reserved for the hint during the
+ // appearance animation of the RemoteInputView
+ hint = 0;
+ }
} else if (mExpandedChild != null) {
hint = getViewHeight(VISIBLE_TYPE_EXPANDED);
} else if (mContractedChild != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 9f5ad1c..d8a8c5d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -143,6 +143,7 @@
private NotificationViewWrapper mWrapper;
private Integer mDefocusTargetHeight = null;
+ private boolean mIsAnimatingAppearance = false;
// TODO(b/193539698): remove this; views shouldn't have access to their controller, and places
@@ -418,6 +419,10 @@
return true;
}
+ public boolean isAnimatingAppearance() {
+ return mIsAnimatingAppearance;
+ }
+
/**
* View will ensure to use at most the provided defocusTargetHeight, when defocusing animated.
* This is to ensure that the parent can resize itself to the targetHeight while the defocus
@@ -624,8 +629,16 @@
animator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
animator.start();
} else if (mIsFocusAnimationFlagActive && getVisibility() != VISIBLE) {
+ mIsAnimatingAppearance = true;
setAlpha(0f);
- getFocusAnimator(crossFadeView).start();
+ Animator focusAnimator = getFocusAnimator(crossFadeView);
+ focusAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation, boolean isReverse) {
+ mIsAnimatingAppearance = false;
+ }
+ });
+ focusAnimator.start();
}
focus();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
index 1fe2008..2c47204 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
@@ -21,7 +21,9 @@
import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -392,12 +394,15 @@
// Start focus animation
view.focusAnimated(crossFadeView);
+ assertTrue(view.isAnimatingAppearance());
+
// fast forward to end of animation
mAnimatorTestRule.advanceTimeBy(ANIMATION_DURATION_STANDARD);
// assert that crossFadeView's alpha is reset to 1f after the animation (hidden behind
// RemoteInputView)
assertEquals(1f, crossFadeView.getAlpha());
+ assertFalse(view.isAnimatingAppearance());
assertEquals(View.VISIBLE, view.getVisibility());
assertEquals(1f, view.getAlpha());
}