summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Selim Cinek <cinek@google.com> 2021-06-16 13:29:14 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2021-06-16 13:29:14 +0000
commit4721ef7c65aff407d9f10e9ca0bcef4825e5f858 (patch)
treea18a59cb9ff14da221f863d8eb1341de90be0dae
parent0ecbcfd09cc6a18fa6c8a1fc53710f8313fab95e (diff)
parent982d5430b8469bf45bbaa5d6009d04e08cf2aac4 (diff)
Merge changes from topic "notif_smooth_dismissal" into sc-dev
* changes: Animating when the qs boundary changes due to notification interactions When swiping notifications it doesn't clip early anymore Modified the way the notifications clip to the boundary
-rw-r--r--packages/SystemUI/res/values/config.xml4
-rw-r--r--packages/SystemUI/src/com/android/systemui/SwipeHelper.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java82
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java78
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java257
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java56
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java16
17 files changed, 377 insertions, 261 deletions
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index b4deaa0af543..82ce881b2fbc 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -396,10 +396,6 @@
<!-- Whether or not the notifications should always fade as they are dismissed. -->
<bool name="config_fadeNotificationsOnDismiss">false</bool>
- <!-- Whether or not the parent of the notification row itself is being translated when swiped or
- its children views. If true, then the contents are translated and vice versa. -->
- <bool name="config_translateNotificationContentsOnSwipe">true</bool>
-
<!-- Whether or not the fade on the notification is based on the amount that it has been swiped
off-screen. -->
<bool name="config_fadeDependingOnAmountSwiped">false</bool>
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index b0f4da251208..affad7a57d86 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -391,9 +391,9 @@ public class SwipeHelper implements Gefingerpoken {
boolean animateLeft = (Math.abs(velocity) > getEscapeVelocity() && velocity < 0) ||
(getTranslation(animView) < 0 && !isDismissAll);
if (animateLeft || animateLeftForRtl || animateUpForMenu) {
- newPos = -getSize(animView);
+ newPos = -getTotalTranslationLength(animView);
} else {
- newPos = getSize(animView);
+ newPos = getTotalTranslationLength(animView);
}
long duration;
if (fixedDuration == 0) {
@@ -470,6 +470,15 @@ public class SwipeHelper implements Gefingerpoken {
}
/**
+ * Get the total translation length where we want to swipe to when dismissing the view. By
+ * default this is the size of the view, but can also be larger.
+ * @param animView the view to ask about
+ */
+ protected float getTotalTranslationLength(View animView) {
+ return getSize(animView);
+ }
+
+ /**
* Called to update the dismiss animation.
*/
protected void prepareDismissAnimation(View view, Animator anim) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
index aef01e9bd811..0fb1c54bb150 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
@@ -71,11 +71,11 @@ public final class NotificationClicker implements View.OnClickListener {
// Check if the notification is displaying the menu, if so slide notification back
if (isMenuVisible(row)) {
mLogger.logMenuVisible(entry);
- row.animateTranslateNotification(0);
+ row.animateResetTranslation();
return;
} else if (row.isChildInGroup() && isMenuVisible(row.getNotificationParent())) {
mLogger.logParentMenuVisible(entry);
- row.getNotificationParent().animateTranslateNotification(0);
+ row.getNotificationParent().animateResetTranslation();
return;
} else if (row.isSummaryWithChildren() && row.areChildrenExpanded()) {
// We never want to open the app directly if the user clicks in between
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 413662447028..c24c2be3faa3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -330,30 +330,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
}
}
- @Override
- public void setDistanceToTopRoundness(float distanceToTopRoundness) {
- super.setDistanceToTopRoundness(distanceToTopRoundness);
- mBackgroundNormal.setDistanceToTopRoundness(distanceToTopRoundness);
- }
-
- /** Sets whether this view is the last notification in a section. */
- @Override
- public void setLastInSection(boolean lastInSection) {
- if (lastInSection != mLastInSection) {
- super.setLastInSection(lastInSection);
- mBackgroundNormal.setLastInSection(lastInSection);
- }
- }
-
- /** Sets whether this view is the first notification in a section. */
- @Override
- public void setFirstInSection(boolean firstInSection) {
- if (firstInSection != mFirstInSection) {
- super.setFirstInSection(firstInSection);
- mBackgroundNormal.setFirstInSection(firstInSection);
- }
- }
-
/**
* Set an override tint color that is used for the background.
*
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 6fd556763943..ba28dc59def4 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
@@ -846,8 +846,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
updateClickAndFocus();
if (mNotificationParent != null) {
setOverrideTintColor(NO_COLOR, 0.0f);
- // Let's reset the distance to top roundness, as this isn't applied to group children
- setDistanceToTopRoundness(NO_ROUNDNESS);
mNotificationParent.updateBackgroundForGroupState();
}
updateBackgroundClipping();
@@ -876,7 +874,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
@Override
protected boolean handleSlideBack() {
if (mMenuRow != null && mMenuRow.isMenuVisible()) {
- animateTranslateNotification(0 /* targetLeft */);
+ animateResetTranslation();
return true;
}
return false;
@@ -1713,21 +1711,17 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mChildrenContainer.setContainingNotification(ExpandableNotificationRow.this);
mChildrenContainer.onNotificationUpdated();
- if (mShouldTranslateContents) {
- mTranslateableViews.add(mChildrenContainer);
- }
+ mTranslateableViews.add(mChildrenContainer);
});
- if (mShouldTranslateContents) {
- // Add the views that we translate to reveal the menu
- mTranslateableViews = new ArrayList<>();
- for (int i = 0; i < getChildCount(); i++) {
- mTranslateableViews.add(getChildAt(i));
- }
- // Remove views that don't translate
- mTranslateableViews.remove(mChildrenContainerStub);
- mTranslateableViews.remove(mGutsStub);
+ // Add the views that we translate to reveal the menu
+ mTranslateableViews = new ArrayList<>();
+ for (int i = 0; i < getChildCount(); i++) {
+ mTranslateableViews.add(getChildAt(i));
}
+ // Remove views that don't translate
+ mTranslateableViews.remove(mChildrenContainerStub);
+ mTranslateableViews.remove(mGutsStub);
}
private void doLongClickCallback() {
@@ -1805,7 +1799,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mTranslateAnim.cancel();
}
- if (!mShouldTranslateContents) {
+ if (mDismissUsingRowTranslationX) {
setTranslationX(0);
} else if (mTranslateableViews != null) {
for (int i = 0; i < mTranslateableViews.size(); i++) {
@@ -1867,23 +1861,47 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
return mPrivateLayout.getActiveRemoteInputText();
}
- public void animateTranslateNotification(final float leftTarget) {
+ /**
+ * Reset the translation with an animation.
+ */
+ public void animateResetTranslation() {
if (mTranslateAnim != null) {
mTranslateAnim.cancel();
}
- mTranslateAnim = getTranslateViewAnimator(leftTarget, null /* updateListener */);
+ mTranslateAnim = getTranslateViewAnimator(0, null /* updateListener */);
if (mTranslateAnim != null) {
mTranslateAnim.start();
}
}
+ /**
+ * Set the dismiss behavior of the view.
+ * @param usingRowTranslationX {@code true} if the view should translate using regular
+ * translationX, otherwise the contents will be
+ * translated.
+ */
+ @Override
+ public void setDismissUsingRowTranslationX(boolean usingRowTranslationX) {
+ if (usingRowTranslationX != mDismissUsingRowTranslationX) {
+ // In case we were already transitioning, let's switch over!
+ float previousTranslation = getTranslation();
+ if (previousTranslation != 0) {
+ setTranslation(0);
+ }
+ super.setDismissUsingRowTranslationX(usingRowTranslationX);
+ if (previousTranslation != 0) {
+ setTranslation(previousTranslation);
+ }
+ }
+ }
+
@Override
public void setTranslation(float translationX) {
invalidate();
if (isBlockingHelperShowingAndTranslationFinished()) {
mGuts.setTranslationX(translationX);
return;
- } else if (!mShouldTranslateContents) {
+ } else if (mDismissUsingRowTranslationX) {
setTranslationX(translationX);
} else if (mTranslateableViews != null) {
// Translate the group of views
@@ -1907,7 +1925,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
@Override
public float getTranslation() {
- if (!mShouldTranslateContents) {
+ if (mDismissUsingRowTranslationX) {
return getTranslationX();
}
@@ -2898,7 +2916,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
float y = event.getY();
NotificationViewWrapper wrapper = getVisibleNotificationViewWrapper();
NotificationHeaderView header = wrapper == null ? null : wrapper.getNotificationHeader();
- if (header != null && header.isInTouchRect(x - getTranslation(), y)) {
+ // the extra translation only needs to be added, if we're translating the notification
+ // contents, otherwise the motionEvent is already at the right place due to the
+ // touch event system.
+ float translation = !mDismissUsingRowTranslationX ? getTranslation() : 0;
+ if (header != null && header.isInTouchRect(x - translation, y)) {
return true;
}
if ((!mIsSummaryWithChildren || shouldShowPublic())
@@ -3037,24 +3059,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
@Override
- public boolean topAmountNeedsClipping() {
- if (isGroupExpanded()) {
- return true;
- }
- if (isGroupExpansionChanging()) {
- return true;
- }
- if (getShowingLayout().shouldClipToRounding(true /* topRounded */,
- false /* bottomRounded */)) {
- return true;
- }
- if (mGuts != null && mGuts.getAlpha() != 0.0f) {
- return true;
- }
- return false;
- }
-
- @Override
protected boolean childNeedsClipping(View child) {
if (child instanceof NotificationContentView) {
NotificationContentView contentView = (NotificationContentView) child;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java
index 5134c62dc182..d58fe3b3c4a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java
@@ -71,21 +71,19 @@ public abstract class ExpandableOutlineView extends ExpandableView {
private int mBackgroundTop;
/**
- * {@code true} if the children views of the {@link ExpandableOutlineView} are translated when
+ * {@code false} if the children views of the {@link ExpandableOutlineView} are translated when
* it is moved. Otherwise, the translation is set on the {@code ExpandableOutlineView} itself.
*/
- protected boolean mShouldTranslateContents;
- private boolean mTopAmountRounded;
- private float mDistanceToTopRoundness = -1;
+ protected boolean mDismissUsingRowTranslationX = true;
private float[] mTmpCornerRadii = new float[8];
private final ViewOutlineProvider mProvider = new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
if (!mCustomOutline && getCurrentTopRoundness() == 0.0f
- && getCurrentBottomRoundness() == 0.0f && !mAlwaysRoundBothCorners
- && !mTopAmountRounded) {
- int translation = mShouldTranslateContents ? (int) getTranslation() : 0;
+ && getCurrentBottomRoundness() == 0.0f && !mAlwaysRoundBothCorners) {
+ // Only when translating just the contents, does the outline need to be shifted.
+ int translation = !mDismissUsingRowTranslationX ? (int) getTranslation() : 0;
int left = Math.max(translation, 0);
int top = mClipTopAmount + mBackgroundTop;
int right = getWidth() + Math.min(translation, 0);
@@ -110,7 +108,9 @@ public abstract class ExpandableOutlineView extends ExpandableView {
float topRoundness = mAlwaysRoundBothCorners
? mOutlineRadius : getCurrentBackgroundRadiusTop();
if (!mCustomOutline) {
- int translation = mShouldTranslateContents && !ignoreTranslation
+ // The outline just needs to be shifted if we're translating the contents. Otherwise
+ // it's already in the right place.
+ int translation = !mDismissUsingRowTranslationX && !ignoreTranslation
? (int) getTranslation() : 0;
int halfExtraWidth = (int) (mExtraWidthForClipping / 2.0f);
left = Math.max(translation, 0) - halfExtraWidth;
@@ -168,33 +168,15 @@ public abstract class ExpandableOutlineView extends ExpandableView {
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
canvas.save();
- Path intersectPath = null;
- if (mTopAmountRounded && topAmountNeedsClipping()) {
- int left = (int) (- mExtraWidthForClipping / 2.0f);
- int top = (int) (mClipTopAmount - mDistanceToTopRoundness);
- int right = getWidth() + (int) (mExtraWidthForClipping + left);
- int bottom = (int) Math.max(mMinimumHeightForClipping,
- Math.max(getActualHeight() - mClipBottomAmount, top + mOutlineRadius));
- getRoundedRectPath(left, top, right, bottom, mOutlineRadius, 0.0f, mClipPath);
- intersectPath = mClipPath;
- }
- boolean clipped = false;
if (childNeedsClipping(child)) {
Path clipPath = getCustomClipPath(child);
if (clipPath == null) {
clipPath = getClipPath(false /* ignoreTranslation */);
}
if (clipPath != null) {
- if (intersectPath != null) {
- clipPath.op(intersectPath, Path.Op.INTERSECT);
- }
canvas.clipPath(clipPath);
- clipped = true;
}
}
- if (!clipped && intersectPath != null) {
- canvas.clipPath(intersectPath);
- }
boolean result = super.drawChild(canvas, child, drawingTime);
canvas.restore();
return result;
@@ -212,32 +194,19 @@ public abstract class ExpandableOutlineView extends ExpandableView {
invalidate();
}
- @Override
- public void setDistanceToTopRoundness(float distanceToTopRoundness) {
- super.setDistanceToTopRoundness(distanceToTopRoundness);
- if (distanceToTopRoundness != mDistanceToTopRoundness) {
- mTopAmountRounded = distanceToTopRoundness >= 0;
- mDistanceToTopRoundness = distanceToTopRoundness;
- applyRoundness();
- }
- }
-
protected boolean childNeedsClipping(View child) {
return false;
}
- public boolean topAmountNeedsClipping() {
- return true;
- }
-
protected boolean isClippingNeeded() {
- return mAlwaysRoundBothCorners || mCustomOutline || getTranslation() != 0 ;
+ // When translating the contents instead of the overall view, we need to make sure we clip
+ // rounded to the contents.
+ boolean forTranslation = getTranslation() != 0 && !mDismissUsingRowTranslationX;
+ return mAlwaysRoundBothCorners || mCustomOutline || forTranslation;
}
private void initDimens() {
Resources res = getResources();
- mShouldTranslateContents =
- res.getBoolean(R.bool.config_translateNotificationContentsOnSwipe);
mOutlineRadius = res.getDimension(R.dimen.notification_shadow_radius);
mAlwaysRoundBothCorners = res.getBoolean(R.bool.config_clipNotificationsToOutline);
if (!mAlwaysRoundBothCorners) {
@@ -272,11 +241,6 @@ public abstract class ExpandableOutlineView extends ExpandableView {
}
public float getCurrentBackgroundRadiusTop() {
- // If this view is top amount notification view, it should always has round corners on top.
- // It will be applied with applyRoundness()
- if (mTopAmountRounded) {
- return mOutlineRadius;
- }
return getCurrentTopRoundness() * mOutlineRadius;
}
@@ -382,9 +346,25 @@ public abstract class ExpandableOutlineView extends ExpandableView {
}
}
+ /**
+ * Set the dismiss behavior of the view.
+ * @param usingRowTranslationX {@code true} if the view should translate using regular
+ * translationX, otherwise the contents will be
+ * translated.
+ */
+ public void setDismissUsingRowTranslationX(boolean usingRowTranslationX) {
+ mDismissUsingRowTranslationX = usingRowTranslationX;
+ }
+
@Override
public int getOutlineTranslation() {
- return mCustomOutline ? mOutlineRect.left : (int) getTranslation();
+ if (mCustomOutline) {
+ return mOutlineRect.left;
+ }
+ if (mDismissUsingRowTranslationX) {
+ return 0;
+ }
+ return (int) getTranslation();
}
public void updateOutline() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index 763d197847c3..8b0764b1c313 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -46,7 +46,6 @@ import java.util.List;
public abstract class ExpandableView extends FrameLayout implements Dumpable {
private static final String TAG = "ExpandableView";
- public static final float NO_ROUNDNESS = -1;
protected OnHeightChangedListener mOnHeightChangedListener;
private int mActualHeight;
protected int mClipTopAmount;
@@ -192,14 +191,6 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable {
}
}
- /**
- * Set the distance to the top roundness, from where we should start clipping a value above
- * or equal to 0 is the effective distance, and if a value below 0 is received, there should
- * be no clipping.
- */
- public void setDistanceToTopRoundness(float distanceToTopRoundness) {
- }
-
public void setActualHeight(int actualHeight) {
setActualHeight(actualHeight, true /* notifyListeners */);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
index 4b1f679b8851..754de580cd61 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
@@ -42,10 +42,8 @@ public class NotificationBackgroundView extends View {
private int mActualHeight;
private int mClipBottomAmount;
private int mTintColor;
- private float[] mCornerRadii = new float[8];
+ private final float[] mCornerRadii = new float[8];
private boolean mBottomIsRounded;
- private boolean mLastInSection;
- private boolean mFirstInSection;
private int mBackgroundTop;
private boolean mBottomAmountClips = true;
private boolean mExpandAnimationRunning;
@@ -53,9 +51,6 @@ public class NotificationBackgroundView extends View {
private int mDrawableAlpha = 255;
private boolean mIsPressedAllowed;
- private boolean mTopAmountRounded;
- private float mDistanceToTopRoundness;
-
public NotificationBackgroundView(Context context, AttributeSet attrs) {
super(context, attrs);
mDontModifyCorners = getResources().getBoolean(
@@ -90,15 +85,6 @@ public class NotificationBackgroundView extends View {
left = (int) ((getWidth() - mActualWidth) / 2.0f);
right = (int) (left + mActualWidth);
}
- if (mTopAmountRounded) {
- int clipTop = (int) (mClipTopAmount - mDistanceToTopRoundness);
- if (clipTop >= 0 || !mFirstInSection) {
- top += clipTop;
- }
- if (clipTop >= 0 && !mLastInSection) {
- bottom += clipTop;
- }
- }
drawable.setBounds(left, top, right, bottom);
drawable.draw(canvas);
}
@@ -180,14 +166,6 @@ public class NotificationBackgroundView extends View {
invalidate();
}
- public void setDistanceToTopRoundness(float distanceToTopRoundness) {
- if (distanceToTopRoundness != mDistanceToTopRoundness) {
- mTopAmountRounded = distanceToTopRoundness >= 0;
- mDistanceToTopRoundness = distanceToTopRoundness;
- invalidate();
- }
- }
-
@Override
public boolean hasOverlappingRendering() {
@@ -246,18 +224,6 @@ public class NotificationBackgroundView extends View {
}
}
- /** Sets whether this background belongs to the last notification in a section. */
- public void setLastInSection(boolean lastInSection) {
- mLastInSection = lastInSection;
- invalidate();
- }
-
- /** Sets whether this background belongs to the first notification in a section. */
- public void setFirstInSection(boolean firstInSection) {
- mFirstInSection = firstInSection;
- invalidate();
- }
-
private void updateBackgroundRadii() {
if (mDontModifyCorners) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index 0c86262d9037..6822d24947c3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -75,7 +75,6 @@ public class AmbientState {
private int mExpandAnimationTopChange;
private ExpandableNotificationRow mExpandingNotification;
private float mHideAmount;
- private float mNotificationScrimTop;
private boolean mAppearing;
private float mPulseHeight = MAX_PULSE_HEIGHT;
private float mDozeAmount = 0.0f;
@@ -256,20 +255,6 @@ public class AmbientState {
return mHideAmount;
}
- /**
- * Set y position of top of notifications background scrim, relative to top of screen.
- */
- public void setNotificationScrimTop(float notificationScrimTop) {
- mNotificationScrimTop = notificationScrimTop;
- }
-
- /**
- * @return Y position of top of notifications background scrim, relative to top of screen.
- */
- public float getNotificationScrimTop() {
- return mNotificationScrimTop;
- }
-
public void setHideSensitive(boolean hideSensitive) {
mHideSensitive = hideSensitive;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index f90b4c079c50..d79c57565dcd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -40,6 +40,7 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Outline;
import android.graphics.Paint;
+import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Bundle;
@@ -424,13 +425,19 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
private final Rect mBackgroundAnimationRect = new Rect();
private ArrayList<BiConsumer<Float, Float>> mExpandedHeightListeners = new ArrayList<>();
private int mHeadsUpInset;
+
+ /**
+ * The position of the scroll boundary relative to this view. This is where the notifications
+ * stop scrolling and will start to clip instead.
+ */
+ private int mQsScrollBoundaryPosition;
private HeadsUpAppearanceController mHeadsUpAppearanceController;
private final Rect mTmpRect = new Rect();
private DismissListener mDismissListener;
private DismissAllAnimationListener mDismissAllAnimationListener;
private NotificationRemoteInputManager mRemoteInputManager;
private ShadeController mShadeController;
- private Runnable mOnStackYChanged;
+ private Consumer<Boolean> mOnStackYChanged;
protected boolean mClearAllEnabled;
@@ -453,6 +460,38 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
private NotificationStackScrollLayoutController mController;
private boolean mKeyguardMediaControllorVisible;
+
+ /**
+ * The clip path used to clip the view in a rounded way.
+ */
+ private final Path mRoundedClipPath = new Path();
+
+ /**
+ * Should we use rounded rect clipping right now
+ */
+ private boolean mShouldUseRoundedRectClipping = false;
+
+ private int mRoundedRectClippingLeft;
+ private int mRoundedRectClippingTop;
+ private int mRoundedRectClippingBottom;
+ private int mRoundedRectClippingRight;
+ private float[] mBgCornerRadii = new float[8];
+
+ /**
+ * Whether stackY should be animated in case the view is getting shorter than the scroll
+ * position and this scrolling will lead to the top scroll inset getting smaller.
+ */
+ private boolean mAnimateStackYForContentHeightChange = false;
+
+ /**
+ * Are we launching a notification right now
+ */
+ private boolean mLaunchingNotification;
+
+ /**
+ * Do notifications dismiss with normal transitioning
+ */
+ private boolean mDismissUsingRowTranslationX = true;
private NotificationEntry mTopHeadsUpEntry;
private long mNumHeadsUp;
private NotificationStackScrollLayoutController.TouchHandler mTouchHandler;
@@ -506,7 +545,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mSectionsManager = notificationSectionsManager;
mFeatureFlags = featureFlags;
mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
- mShouldUseSplitNotificationShade = shouldUseSplitNotificationShade(mFeatureFlags, res);
+ updateSplitNotificationShade();
mSectionsManager.initialize(this, LayoutInflater.from(context));
mSections = mSectionsManager.createSectionsForBuckets();
@@ -862,6 +901,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mCornerRadius = res.getDimensionPixelSize(R.dimen.notification_corner_radius);
mHeadsUpInset = mStatusBarHeight + res.getDimensionPixelSize(
R.dimen.heads_up_status_bar_padding);
+ mQsScrollBoundaryPosition = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.quick_qs_offset_height);
}
void updateCornerRadius() {
@@ -961,6 +1002,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
updateFirstAndLastBackgroundViews();
updateAlgorithmLayoutMinHeight();
updateOwnTranslationZ();
+
+ // Once the layout has finished, we don't need to animate any scrolling clampings anymore.
+ mAnimateStackYForContentHeightChange = false;
}
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
@@ -1017,33 +1061,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void onPreDrawDuringAnimation() {
mShelf.updateAppearance();
- updateClippingToTopRoundedCorner();
if (!mNeedsAnimation && !mChildrenUpdateRequested) {
updateBackground();
}
}
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- private void updateClippingToTopRoundedCorner() {
- Float clipStart = mAmbientState.getNotificationScrimTop();
- Float clipEnd = clipStart + mCornerRadius;
- boolean first = true;
- for (int i = 0; i < getChildCount(); i++) {
- ExpandableView child = (ExpandableView) getChildAt(i);
- if (child.getVisibility() == GONE) {
- continue;
- }
- float start = child.getTranslationY();
- float end = start + child.getActualHeight();
- boolean clip = clipStart > start && clipStart < end
- || clipEnd >= start && clipEnd <= end;
- clip &= !(first && mScrollAdapter.isScrolledToTop());
- child.setDistanceToTopRoundness(clip ? Math.max(start - clipStart, 0)
- : ExpandableView.NO_ROUNDNESS);
- first = false;
- }
- }
-
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void updateScrollStateForAddedChildren() {
if (mChildrenToAddAnimated.isEmpty()) {
@@ -1117,7 +1139,13 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
private void clampScrollPosition() {
int scrollRange = getScrollRange();
if (scrollRange < mOwnScrollY) {
- setOwnScrollY(scrollRange);
+ boolean animateStackY = false;
+ if (scrollRange < getScrollAmountToScrollBoundary()
+ && mAnimateStackYForContentHeightChange) {
+ // if the scroll boundary updates the position of the stack,
+ animateStackY = true;
+ }
+ setOwnScrollY(scrollRange, animateStackY);
}
}
@@ -1146,6 +1174,14 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
* Apply expansion fraction to the y position and height of the notifications panel.
*/
private void updateStackPosition() {
+ updateStackPosition(false /* listenerNeedsAnimation */);
+ }
+
+ /**
+ * Apply expansion fraction to the y position and height of the notifications panel.
+ * @param listenerNeedsAnimation does the listener need to animate?
+ */
+ private void updateStackPosition(boolean listenerNeedsAnimation) {
// Consider interpolating from an mExpansionStartY for use on lockscreen and AOD
float endTopPosition = mTopPadding + mExtraTopInsetForFullShadeTransition
+ mAmbientState.getOverExpansion();
@@ -1153,7 +1189,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
final float stackY = MathUtils.lerp(0, endTopPosition, fraction);
mAmbientState.setStackY(stackY);
if (mOnStackYChanged != null) {
- mOnStackYChanged.run();
+ mOnStackYChanged.accept(listenerNeedsAnimation);
}
if (mQsExpansionFraction <= 0) {
final float stackEndHeight = Math.max(0f,
@@ -1165,7 +1201,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
}
- void setOnStackYChanged(Runnable onStackYChanged) {
+ /**
+ * Add a listener when the StackY changes. The argument signifies whether an animation is
+ * needed.
+ */
+ void setOnStackYChanged(Consumer<Boolean> onStackYChanged) {
mOnStackYChanged = onStackYChanged;
}
@@ -1600,7 +1640,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Resources res = getResources();
- mShouldUseSplitNotificationShade = shouldUseSplitNotificationShade(mFeatureFlags, res);
+ updateSplitNotificationShade();
mStatusBarHeight = res.getDimensionPixelOffset(R.dimen.status_bar_height);
float densityScale = res.getDisplayMetrics().density;
mSwipeHelper.setDensityScale(densityScale);
@@ -2527,8 +2567,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
updateScrollStateForRemovedChild(child);
boolean animationGenerated = generateRemoveAnimation(child);
if (animationGenerated) {
- if (!mSwipedOutViews.contains(child)
- || Math.abs(child.getTranslation()) != child.getWidth()) {
+ if (!mSwipedOutViews.contains(child) || !isFullySwipedOut(child)) {
container.addTransientView(child, 0);
child.setTransientContainer(container);
}
@@ -2540,6 +2579,13 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
focusNextViewIfFocused(child);
}
+ /**
+ * Has this view been fully swiped out such that it's not visible anymore.
+ */
+ public boolean isFullySwipedOut(ExpandableView child) {
+ return Math.abs(child.getTranslation()) >= Math.abs(getTotalTranslationLength(child));
+ }
+
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void focusNextViewIfFocused(View view) {
if (view instanceof ExpandableNotificationRow) {
@@ -2659,17 +2705,27 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
final int startingPosition = getPositionInLinearLayout(removedChild);
final int childHeight = getIntrinsicHeight(removedChild) + mPaddingBetweenElements;
final int endPosition = startingPosition + childHeight;
- if (endPosition <= mOwnScrollY) {
+ final int scrollBoundaryStart = getScrollAmountToScrollBoundary();
+ mAnimateStackYForContentHeightChange = true;
+ // This is reset onLayout
+ if (endPosition <= mOwnScrollY - scrollBoundaryStart) {
// This child is fully scrolled of the top, so we have to deduct its height from the
// scrollPosition
setOwnScrollY(mOwnScrollY - childHeight);
- } else if (startingPosition < mOwnScrollY) {
+ } else if (startingPosition < mOwnScrollY - scrollBoundaryStart) {
// This child is currently being scrolled into, set the scroll position to the
// start of this child
- setOwnScrollY(startingPosition);
+ setOwnScrollY(startingPosition + scrollBoundaryStart);
}
}
+ /**
+ * @return the amount of scrolling needed to start clipping notifications.
+ */
+ private int getScrollAmountToScrollBoundary() {
+ return mTopPadding - mQsScrollBoundaryPosition;
+ }
+
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
private int getIntrinsicHeight(View view) {
if (view instanceof ExpandableView) {
@@ -2758,7 +2814,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
updateAnimationState(child);
updateChronometerForChild(child);
if (child instanceof ExpandableNotificationRow) {
- ((ExpandableNotificationRow) child).setDismissRtl(mDismissRtl);
+ ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+ row.setDismissRtl(mDismissRtl);
+ row.setDismissUsingRowTranslationX(mDismissUsingRowTranslationX);
+
}
}
@@ -2818,6 +2877,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void applyExpandAnimationParams(ExpandAnimationParameters params) {
mAmbientState.setExpandAnimationTopChange(params == null ? 0 : params.getTopChange());
+
+ // Disable clipping for launches
+ setLaunchingNotification(params != null);
requestChildrenUpdate();
}
@@ -2901,7 +2963,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mAnimationEvents.clear();
updateBackground();
updateViewShadows();
- updateClippingToTopRoundedCorner();
} else {
applyCurrentState();
}
@@ -3030,7 +3091,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
removedTranslation = row.getTranslationWhenRemoved();
ignoreChildren = false;
}
- childWasSwipedOut |= Math.abs(row.getTranslation()) == row.getWidth();
+ childWasSwipedOut |= isFullySwipedOut(row);
} else if (child instanceof MediaHeaderView) {
childWasSwipedOut = true;
}
@@ -3038,11 +3099,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
Rect clipBounds = child.getClipBounds();
childWasSwipedOut = clipBounds != null && clipBounds.height() == 0;
- if (childWasSwipedOut && child instanceof ExpandableView) {
+ if (childWasSwipedOut) {
// Clean up any potential transient views if the child has already been swiped
// out, as we won't be animating it further (due to its height already being
// clipped to 0.
- ViewGroup transientContainer = ((ExpandableView) child).getTransientContainer();
+ ViewGroup transientContainer = child.getTransientContainer();
if (transientContainer != null) {
transientContainer.removeTransientView(child);
}
@@ -3795,6 +3856,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
updateNotificationAnimationStates();
updateChronometers();
requestChildrenUpdate();
+ updateUseRoundedRectClipping();
}
}
@@ -3815,6 +3877,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
void onChildHeightChanged(ExpandableView view, boolean needsAnimation) {
+ boolean previouslyNeededAnimation = mAnimateStackYForContentHeightChange;
+ if (needsAnimation) {
+ mAnimateStackYForContentHeightChange = true;
+ }
updateContentHeight();
updateScrollPositionOnExpandInBottom(view);
clampScrollPosition();
@@ -3835,6 +3901,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
requestAnimationOnViewResize(row);
}
requestChildrenUpdate();
+ mAnimateStackYForContentHeightChange = previouslyNeededAnimation;
}
void onChildHeightReset(ExpandableView view) {
@@ -4015,7 +4082,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
setAnimationRunning(false);
updateBackground();
updateViewShadows();
- updateClippingToTopRoundedCorner();
}
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
@@ -4048,7 +4114,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
expandableView.setFakeShadowIntensity(
diff / FakeShadowView.SHADOW_SIBLING_TRESHOLD,
previous.getOutlineAlpha(), (int) yLocation,
- previous.getOutlineTranslation());
+ (int) (previous.getOutlineTranslation() + previous.getTranslation()));
}
previous = expandableView;
}
@@ -4550,6 +4616,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setQsExpansionFraction(float qsExpansionFraction) {
mQsExpansionFraction = qsExpansionFraction;
+ updateUseRoundedRectClipping();
// If notifications are scrolled,
// clear out scrollY by the time we push notifications offscreen
@@ -4560,13 +4627,18 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void setOwnScrollY(int ownScrollY) {
+ setOwnScrollY(ownScrollY, false /* animateScrollChangeListener */);
+ }
+
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
+ private void setOwnScrollY(int ownScrollY, boolean animateStackYChangeListener) {
if (ownScrollY != mOwnScrollY) {
// We still want to call the normal scrolled changed for accessibility reasons
onScrollChanged(mScrollX, ownScrollY, mScrollX, mOwnScrollY);
mOwnScrollY = ownScrollY;
mAmbientState.setScrollY(mOwnScrollY);
updateOnScrollChange();
- updateStackPosition();
+ updateStackPosition(animateStackYChangeListener);
}
}
@@ -4632,6 +4704,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mStatusBarState = statusBarState;
mAmbientState.setStatusBarState(statusBarState);
updateSpeedBumpIndex();
+ updateDismissBehavior();
}
void onStatePostChange(boolean fromShadeLocked) {
@@ -5192,6 +5265,108 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
/**
+ * Set rounded rect clipping bounds on this view.
+ */
+ public void setRoundedClippingBounds(int left, int top, int right, int bottom, int topRadius,
+ int bottomRadius) {
+ if (mRoundedRectClippingLeft == left && mRoundedRectClippingRight == right
+ && mRoundedRectClippingBottom == bottom && mRoundedRectClippingTop == top
+ && mBgCornerRadii[0] == topRadius && mBgCornerRadii[5] == bottomRadius) {
+ return;
+ }
+ mRoundedRectClippingLeft = left;
+ mRoundedRectClippingTop = top;
+ mRoundedRectClippingBottom = bottom;
+ mRoundedRectClippingRight = right;
+ mBgCornerRadii[0] = topRadius;
+ mBgCornerRadii[1] = topRadius;
+ mBgCornerRadii[2] = topRadius;
+ mBgCornerRadii[3] = topRadius;
+ mBgCornerRadii[4] = bottomRadius;
+ mBgCornerRadii[5] = bottomRadius;
+ mBgCornerRadii[6] = bottomRadius;
+ mBgCornerRadii[7] = bottomRadius;
+ mRoundedClipPath.reset();
+ mRoundedClipPath.addRoundRect(left, top, right, bottom, mBgCornerRadii, Path.Direction.CW);
+ if (mShouldUseRoundedRectClipping) {
+ invalidate();
+ }
+ }
+
+ private void updateSplitNotificationShade() {
+ boolean split = shouldUseSplitNotificationShade(mFeatureFlags, getResources());
+ if (split != mShouldUseSplitNotificationShade) {
+ mShouldUseSplitNotificationShade = split;
+ updateDismissBehavior();
+ updateUseRoundedRectClipping();
+ }
+ }
+
+ private void updateDismissBehavior() {
+ // On the split keyguard, dismissing with clipping without a visual boundary looks odd,
+ // so let's use the content dismiss behavior instead.
+ boolean dismissUsingRowTranslationX = !mShouldUseSplitNotificationShade
+ || mStatusBarState != StatusBarState.KEYGUARD;
+ if (mDismissUsingRowTranslationX != dismissUsingRowTranslationX) {
+ mDismissUsingRowTranslationX = dismissUsingRowTranslationX;
+ for (int i = 0; i < getChildCount(); i++) {
+ View child = getChildAt(i);
+ if (child instanceof ExpandableNotificationRow) {
+ ((ExpandableNotificationRow) child).setDismissUsingRowTranslationX(
+ dismissUsingRowTranslationX);
+ }
+ }
+ }
+ }
+
+ /**
+ * Set if we're launching a notification right now.
+ */
+ private void setLaunchingNotification(boolean launching) {
+ if (launching == mLaunchingNotification) {
+ return;
+ }
+ mLaunchingNotification = launching;
+ updateUseRoundedRectClipping();
+ }
+
+ /**
+ * Should we use rounded rect clipping
+ */
+ private void updateUseRoundedRectClipping() {
+ // We don't want to clip notifications when QS is expanded, because incoming heads up on
+ // the bottom would be clipped otherwise
+ boolean qsAllowsClipping = mQsExpansionFraction < 0.5f || mShouldUseSplitNotificationShade;
+ boolean clip = !mLaunchingNotification && mIsExpanded && qsAllowsClipping;
+ if (clip != mShouldUseRoundedRectClipping) {
+ mShouldUseRoundedRectClipping = clip;
+ invalidate();
+ }
+ }
+
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ if (mShouldUseRoundedRectClipping) {
+ // Let's clip rounded.
+ canvas.clipPath(mRoundedClipPath);
+ }
+ super.dispatchDraw(canvas);
+ }
+
+ /**
+ * Calculate the total translation needed when dismissing.
+ */
+ public float getTotalTranslationLength(View animView) {
+ if (!mDismissUsingRowTranslationX) {
+ return animView.getMeasuredWidth();
+ }
+ float notificationWidth = animView.getMeasuredWidth();
+ int containerWidth = getMeasuredWidth();
+ float padding = (containerWidth - notificationWidth) / 2.0f;
+ return containerWidth - padding;
+ }
+
+ /**
* A listener that is notified when the empty space below the notifications is clicked on
*/
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index dec98887577e..fb4f5592e97f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -384,6 +384,11 @@ public class NotificationStackScrollLayoutController {
}
@Override
+ public float getTotalTranslationLength(View animView) {
+ return mView.getTotalTranslationLength(animView);
+ }
+
+ @Override
public void onSnooze(StatusBarNotification sbn,
NotificationSwipeActionHelper.SnoozeOption snoozeOption) {
mStatusBar.setNotificationSnoozed(sbn, snoozeOption);
@@ -822,8 +827,18 @@ public class NotificationStackScrollLayoutController {
return mView.isLayoutRtl();
}
+ /**
+ * @return the left of the view.
+ */
public int getLeft() {
- return mView.getLeft();
+ return mView.getLeft();
+ }
+
+ /**
+ * @return the top of the view.
+ */
+ public int getTop() {
+ return mView.getTop();
}
public float getTranslationX() {
@@ -1008,7 +1023,7 @@ public class NotificationStackScrollLayoutController {
mView.setQsExpansionFraction(expansionFraction);
}
- public void setOnStackYChanged(Runnable onStackYChanged) {
+ public void setOnStackYChanged(Consumer<Boolean> onStackYChanged) {
mView.setOnStackYChanged(onStackYChanged);
}
@@ -1440,6 +1455,14 @@ public class NotificationStackScrollLayoutController {
}
/**
+ * Set rounded rect clipping bounds on this view.
+ */
+ public void setRoundedClippingBounds(int left, int top, int right, int bottom, int topRadius,
+ int bottomRadius) {
+ mView.setRoundedClippingBounds(left, top, right, bottom, topRadius, bottomRadius);
+ }
+
+ /**
* Enum for UiEvent logged from this class
*/
enum NotificationPanelEvent implements UiEventLogger.UiEventEnum {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
index f4c4d440b063..664776975b24 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
@@ -325,6 +325,11 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc
}
@Override
+ protected float getTotalTranslationLength(View animView) {
+ return mCallback.getTotalTranslationLength(animView);
+ }
+
+ @Override
public void setTranslation(View v, float translate) {
if (v instanceof SwipeableView) {
((SwipeableView) v).setTranslation(translate);
@@ -466,6 +471,13 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc
void onSnooze(StatusBarNotification sbn, SnoozeOption snoozeOption);
void onDismiss();
+
+ /**
+ * Get the total translation length where we want to swipe to when dismissing the view. By
+ * default this is the size of the view, but can also be larger.
+ * @param animView the view to ask about
+ */
+ float getTotalTranslationLength(View animView);
}
static class Builder {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index e5fd103c239f..74e8de4c9d11 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -158,7 +158,7 @@ public class StackScrollAlgorithm {
AmbientState ambientState) {
float drawStart = ambientState.isOnKeyguard() ? 0
: ambientState.getStackY() - ambientState.getScrollY();
- float clipStart = ambientState.getNotificationScrimTop();
+ float clipStart = 0;
int childCount = algorithmState.visibleChildren.size();
boolean firstHeadsUp = true;
for (int i = 0; i < childCount; i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
index 4fd2064b394d..ee12b4b2d728 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
@@ -392,7 +392,7 @@ public class StackStateAnimator {
0, () -> removeTransientView(changingView), null);
} else if (event.animationType ==
NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT) {
- if (Math.abs(changingView.getTranslation()) == changingView.getWidth()
+ if (mHostLayout.isFullySwipedOut(changingView)
&& changingView.getTransientContainer() != null) {
changingView.getTransientContainer().removeTransientView(changingView);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 528827f639dd..35d1526c4c59 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -830,6 +830,7 @@ public class NotificationPanelViewController extends PanelViewController {
mNotificationStackScrollLayoutController.setOverscrollTopChangedListener(
mOnOverscrollTopChangedListener);
mNotificationStackScrollLayoutController.setOnScrollListener(this::onNotificationScrolled);
+ mNotificationStackScrollLayoutController.setOnStackYChanged(this::onStackYChanged);
mNotificationStackScrollLayoutController.setOnEmptySpaceClickListener(
mOnEmptySpaceClickListener);
addTrackingHeadsUpListener(mNotificationStackScrollLayoutController::setTrackingHeadsUp);
@@ -2198,15 +2199,17 @@ public class NotificationPanelViewController extends PanelViewController {
mDepthController.setQsPanelExpansion(qsExpansionFraction);
}
- private Runnable mOnStackYChanged = () -> {
+ private void onStackYChanged(boolean shouldAnimate) {
if (mQs != null) {
+ if (shouldAnimate) {
+ mAnimateNextNotificationBounds = true;
+ mNotificationBoundsAnimationDelay = 0;
+ }
setQSClippingBounds();
}
};
private void onNotificationScrolled(int newScrollPosition) {
- // Since this is an overscroller, sometimes the scrollY can be temporarily negative
- // (when overscrollng on the top and flinging). Let's
updateQSExpansionEnabledAmbient();
}
@@ -2228,14 +2231,13 @@ public class NotificationPanelViewController extends PanelViewController {
* and QS state.
*/
private void setQSClippingBounds() {
- int top = 0;
- int bottom = 0;
- int left = 0;
- int right = 0;
+ int top;
+ int bottom;
+ int left;
+ int right;
final int qsPanelBottomY = calculateQsBottomPosition(computeQsExpansionFraction());
- final boolean visible = (computeQsExpansionFraction() > 0 || qsPanelBottomY > 0)
- && !mShouldUseSplitNotificationShade;
+ final boolean qsVisible = (computeQsExpansionFraction() > 0 || qsPanelBottomY > 0);
if (!mShouldUseSplitNotificationShade) {
if (mTransitioningToFullShadeProgress > 0.0f) {
@@ -2244,7 +2246,6 @@ public class NotificationPanelViewController extends PanelViewController {
top = mTransitionToFullShadeQSPosition;
} else {
final float notificationTop = getQSEdgePosition();
- mAmbientState.setNotificationScrimTop(notificationTop);
top = (int) (isOnKeyguard() ? Math.min(qsPanelBottomY, notificationTop)
: notificationTop);
}
@@ -2252,8 +2253,7 @@ public class NotificationPanelViewController extends PanelViewController {
// notification bounds should take full screen width regardless of insets
left = 0;
right = getView().getRight() + mDisplayRightInset;
- } else if (qsPanelBottomY > 0) { // so bounds are empty on lockscreen
- mAmbientState.setNotificationScrimTop(mSplitShadeNotificationsTopPadding);
+ } else {
top = Math.min(qsPanelBottomY, mSplitShadeNotificationsTopPadding);
bottom = mNotificationStackScrollLayoutController.getHeight();
left = mNotificationStackScrollLayoutController.getLeft();
@@ -2261,17 +2261,17 @@ public class NotificationPanelViewController extends PanelViewController {
}
// top should never be lower than bottom, otherwise it will be invisible.
top = Math.min(top, bottom);
- applyQSClippingBounds(left, top, right, bottom, visible);
+ applyQSClippingBounds(left, top, right, bottom, qsVisible);
}
private void applyQSClippingBounds(int left, int top, int right, int bottom,
- boolean visible) {
+ boolean qsVisible) {
if (!mAnimateNextNotificationBounds || mKeyguardStatusAreaClipBounds.isEmpty()) {
if (mQsClippingAnimation != null) {
// update the end position of the animator
mQsClippingAnimationEndBounds.set(left, top, right, bottom);
} else {
- applyQSClippingImmediately(left, top, right, bottom, visible);
+ applyQSClippingImmediately(left, top, right, bottom, qsVisible);
}
} else {
mQsClippingAnimationEndBounds.set(left, top, right, bottom);
@@ -2295,7 +2295,7 @@ public class NotificationPanelViewController extends PanelViewController {
int animBottom = (int) MathUtils.lerp(startBottom,
mQsClippingAnimationEndBounds.bottom, fraction);
applyQSClippingImmediately(animLeft, animTop, animRight, animBottom,
- visible /* visible */);
+ qsVisible /* qsVisible */);
});
mQsClippingAnimation.addListener(new AnimatorListenerAdapter() {
@Override
@@ -2310,7 +2310,7 @@ public class NotificationPanelViewController extends PanelViewController {
}
private void applyQSClippingImmediately(int left, int top, int right, int bottom,
- boolean visible) {
+ boolean qsVisible) {
// Fancy clipping for quick settings
int radius = mScrimCornerRadius;
int statusBarClipTop = 0;
@@ -2318,19 +2318,34 @@ public class NotificationPanelViewController extends PanelViewController {
if (!mShouldUseSplitNotificationShade) {
// The padding on this area is large enough that we can use a cheaper clipping strategy
mKeyguardStatusAreaClipBounds.set(left, top, right, bottom);
- clipStatusView = visible;
+ clipStatusView = qsVisible;
radius = (int) MathUtils.lerp(mScreenCornerRadius, mScrimCornerRadius,
Math.min(top / (float) mScrimCornerRadius, 1f));
statusBarClipTop = top - mKeyguardStatusBar.getTop();
}
if (mQs != null) {
- mQs.setFancyClipping(top, bottom, radius, visible);
+ mQs.setFancyClipping(top, bottom, radius, qsVisible
+ && !mShouldUseSplitNotificationShade);
}
mKeyguardStatusViewController.setClipBounds(
clipStatusView ? mKeyguardStatusAreaClipBounds : null);
- mScrimController.setNotificationsBounds(left, top, right, bottom);
+ if (!qsVisible && mShouldUseSplitNotificationShade) {
+ // On the lockscreen when qs isn't visible, we don't want the bounds of the shade to
+ // be visible, otherwise you can see the bounds once swiping up to see bouncer
+ mScrimController.setNotificationsBounds(0, 0, 0, 0);
+ } else {
+ mScrimController.setNotificationsBounds(left, top, right, bottom);
+ }
+
mScrimController.setScrimCornerRadius(radius);
mKeyguardStatusBar.setTopClipping(statusBarClipTop);
+ int nsslLeft = left - mNotificationStackScrollLayoutController.getLeft();
+ int nsslRight = right - mNotificationStackScrollLayoutController.getLeft();
+ int nsslTop = top - mNotificationStackScrollLayoutController.getTop();
+ int nsslBottom = bottom - mNotificationStackScrollLayoutController.getTop();
+ int bottomRadius = mShouldUseSplitNotificationShade ? radius : 0;
+ mNotificationStackScrollLayoutController.setRoundedClippingBounds(
+ nsslLeft, nsslTop, nsslRight, nsslBottom, radius, bottomRadius);
}
private float getQSEdgePosition() {
@@ -3323,7 +3338,6 @@ public class NotificationPanelViewController extends PanelViewController {
// The expandedHeight is always the full panel Height when bypassing
expandedHeight = getMaxPanelHeightNonBypass();
}
- mNotificationStackScrollLayoutController.setOnStackYChanged(mOnStackYChanged);
mNotificationStackScrollLayoutController.setExpandedHeight(expandedHeight);
updateKeyguardBottomAreaAlpha();
updateBigClockAlpha();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index 2e0827f24bf8..fa25c3f1e005 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -289,6 +289,7 @@ public class ExpandableNotificationRowTest extends SysuiTestCase {
@Test
public void testIconScrollXAfterTranslationAndReset() throws Exception {
+ mGroupRow.setDismissUsingRowTranslationX(false);
mGroupRow.setTranslation(50);
assertEquals(50, -mGroupRow.getEntry().getIcons().getShelfIcon().getScrollX());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 9e939eefa705..2d51683c8ae5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -84,7 +84,6 @@ import com.android.systemui.media.MediaDataManager;
import com.android.systemui.media.MediaHierarchyManager;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.plugins.qs.QS;
import com.android.systemui.qs.QSDetailDisplayer;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.FeatureFlags;
@@ -675,21 +674,6 @@ public class NotificationPanelViewTest extends SysuiTestCase {
verify(mTapAgainViewController).show();
}
- @Test
- public void testNotificationClipping_isAlignedWithNotificationScrimInSplitShade() {
- mStatusBarStateController.setState(SHADE);
- QS qs = mock(QS.class);
- when(qs.getHeader()).thenReturn(mock(View.class));
- mNotificationPanelViewController.mQs = qs;
- enableSplitShade();
-
- // hacky way to refresh notification scrim top with non-zero qsPanelBottom value
- mNotificationPanelViewController.setTransitionToFullShadeAmount(200, false, 0);
-
- verify(mAmbientState)
- .setNotificationScrimTop(NOTIFICATION_SCRIM_TOP_PADDING_IN_SPLIT_SHADE);
- }
-
private FalsingManager.FalsingTapListener getFalsingTapListener() {
for (View.OnAttachStateChangeListener listener : mOnAttachStateChangeListeners) {
listener.onViewAttachedToWindow(mView);