Don't collapse the Shade when expanding a notification.

This CL prevents the Shade from collapsing if a notification expansion
animation is pending/running. It does so by:

1. Making sure that StatusBarNotificationActivityStarter#shouldCollapse
   is checked *after* ActivityLaunchAnimator#setLaunchResult is called.
2. Updating the clipped area of the parent of the notification that is
   expanding, if any.
3. Not moving the QS or the notification siblings while the animation is
   running.
4. Making sure that the notification is displayed above the QS.

See b/181654098#comment4 for before/after videos.

Bug: 181654098
Test: Manual; atest ActivityLaunchAnimatorTest ExpandableNotificationRowTest NotificationChildrenContainerTest NotificationStackScrollLayoutTest StatusBarNotificationActivityStarterTest

Change-Id: I5a7beb4dc4883ed2757e286c4b480f83709680f7
This commit is contained in:
Jordan Demeulenaere
2021-03-04 14:27:09 +01:00
parent 8eecb94a9a
commit 6a7e3d3682
6 changed files with 39 additions and 49 deletions

View File

@@ -2027,17 +2027,22 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
int top = params.getTop();
float interpolation = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(params.getProgress());
int startClipTopAmount = params.getStartClipTopAmount();
int clipTopAmount = (int) MathUtils.lerp(startClipTopAmount, 0, interpolation);
if (mNotificationParent != null) {
float parentY = mNotificationParent.getTranslationY();
top -= parentY;
mNotificationParent.setTranslationZ(translationZ);
// When the expanding notification is below its parent, the parent must be clipped
// exactly how it was clipped before the animation. When the expanding notification is
// on or above its parent (top <= 0), then the parent must be clipped exactly 'top'
// pixels to show the expanding notification, while still taking the decreasing
// notification clipTopAmount into consideration, so 'top + clipTopAmount'.
int parentStartClipTopAmount = params.getParentStartClipTopAmount();
if (startClipTopAmount != 0) {
int clipTopAmount = (int) MathUtils.lerp(parentStartClipTopAmount,
parentStartClipTopAmount - startClipTopAmount,
interpolation);
mNotificationParent.setClipTopAmount(clipTopAmount);
}
int parentClipTopAmount = Math.min(parentStartClipTopAmount,
top + clipTopAmount);
mNotificationParent.setClipTopAmount(parentClipTopAmount);
mNotificationParent.setExtraWidthForClipping(extraWidthForClipping);
float clipBottom = Math.max(params.getBottom(),
parentY + mNotificationParent.getActualHeight()
@@ -2046,7 +2051,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
int minimumHeightForClipping = (int) (clipBottom - clipTop);
mNotificationParent.setMinimumHeightForClipping(minimumHeightForClipping);
} else if (startClipTopAmount != 0) {
int clipTopAmount = (int) MathUtils.lerp(startClipTopAmount, 0, interpolation);
setClipTopAmount(clipTopAmount);
}
setTranslationY(top);

View File

@@ -34,7 +34,6 @@ import android.widget.RemoteViews;
import android.widget.TextView;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.widget.CachingIconView;
import com.android.internal.widget.NotificationExpandButton;
import com.android.systemui.R;
import com.android.systemui.statusbar.CrossFadeHelper;
@@ -638,10 +637,6 @@ public class NotificationChildrenContainer extends ViewGroup {
childState.location = parentState.location;
childState.inShelf = parentState.inShelf;
yPosition += intrinsicHeight;
if (child.isExpandAnimationRunning()) {
launchTransitionCompensation = -ambientState.getExpandAnimationTopChange();
}
}
if (mOverflowNumber != null) {
ExpandableNotificationRow overflowView = mAttachedChildren.get(Math.min(

View File

@@ -28,14 +28,12 @@ import android.view.ViewGroup;
import com.android.systemui.R;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.row.FooterView;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
@@ -156,7 +154,7 @@ public class StackScrollAlgorithm {
private void updateClipping(StackScrollAlgorithmState algorithmState,
AmbientState ambientState) {
float drawStart = !ambientState.isOnKeyguard() ? ambientState.getTopPadding()
+ ambientState.getStackTranslation() + ambientState.getExpandAnimationTopChange()
+ ambientState.getStackTranslation()
: 0;
float clipStart = 0;
int childCount = algorithmState.visibleChildren.size();
@@ -329,9 +327,6 @@ public class StackScrollAlgorithm {
childViewState.location = ExpandableViewState.LOCATION_MAIN_AREA;
float inset = ambientState.getTopPadding() + ambientState.getStackTranslation()
+ ambientState.getSectionPadding();
if (i <= algorithmState.getIndexOfExpandingNotification()) {
inset += ambientState.getExpandAnimationTopChange();
}
if (child.mustStayOnScreen() && childViewState.yTranslation >= 0) {
// Even if we're not scrolled away we're in view and we're also not in the
// shelf. We can relax the constraints and let us scroll off the top!

View File

@@ -439,7 +439,6 @@ public class NotificationPanelViewController extends PanelViewController {
private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
private boolean mUserSetupComplete;
private int mQsNotificationTopPadding;
private float mExpandOffset;
private boolean mHideIconsDuringNotificationLaunch = true;
private int mStackScrollerMeasuringPass;
private ArrayList<Consumer<ExpandableNotificationRow>>
@@ -2446,8 +2445,7 @@ public class NotificationPanelViewController extends PanelViewController {
}
startHeight = -mQs.getQsMinExpansionHeight();
}
float translation = MathUtils.lerp(startHeight, 0, Math.min(1.0f, appearAmount))
+ mExpandOffset;
float translation = MathUtils.lerp(startHeight, 0, Math.min(1.0f, appearAmount));
return Math.min(0, translation);
}
@@ -3187,16 +3185,16 @@ public class NotificationPanelViewController extends PanelViewController {
}
public void applyExpandAnimationParams(ExpandAnimationParameters params) {
mExpandOffset = params != null ? params.getTopChange() : 0;
updateQsExpansion();
if (params != null) {
boolean hideIcons = params.getProgress(
ActivityLaunchAnimator.ANIMATION_DELAY_ICON_FADE_IN, 100) == 0.0f;
if (hideIcons != mHideIconsDuringNotificationLaunch) {
mHideIconsDuringNotificationLaunch = hideIcons;
if (!hideIcons) {
mCommandQueue.recomputeDisableFlags(mDisplayId, true /* animate */);
}
if (params == null) {
return;
}
boolean hideIcons = params.getProgress(
ActivityLaunchAnimator.ANIMATION_DELAY_ICON_FADE_IN, 100) == 0.0f;
if (hideIcons != mHideIconsDuringNotificationLaunch) {
mHideIconsDuringNotificationLaunch = hideIcons;
if (!hideIcons) {
mCommandQueue.recomputeDisableFlags(mDisplayId, true /* animate */);
}
}
}

View File

@@ -89,30 +89,22 @@ public class NotificationsQuickSettingsContainer extends ConstraintLayout
@Override
protected void dispatchDraw(Canvas canvas) {
// Invert the order of the scroll view and user switcher such that the notifications receive
// touches first but the panel gets drawn above.
mDrawingOrderedChildren.clear();
mLayoutDrawingOrder.clear();
if (mKeyguardStatusBar.getVisibility() == View.VISIBLE) {
mDrawingOrderedChildren.add(mKeyguardStatusBar);
mLayoutDrawingOrder.add(mKeyguardStatusBar);
}
if (mStackScroller.getVisibility() == View.VISIBLE) {
mDrawingOrderedChildren.add(mStackScroller);
mLayoutDrawingOrder.add(mStackScroller);
}
if (mQsFrame.getVisibility() == View.VISIBLE) {
mDrawingOrderedChildren.add(mQsFrame);
mLayoutDrawingOrder.add(mQsFrame);
}
if (mHasViewsAboveShelf) {
// StackScroller needs to be on top
mDrawingOrderedChildren.remove(mStackScroller);
if (mStackScroller.getVisibility() == View.VISIBLE) {
mDrawingOrderedChildren.add(mStackScroller);
mLayoutDrawingOrder.add(mStackScroller);
}
// Let's now find the order that the view has when drawing regulary by sorting
// Let's now find the order that the view has when drawing regularly by sorting
mLayoutDrawingOrder.sort(mIndexComparator);
super.dispatchDraw(canvas);
}

View File

@@ -356,9 +356,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
if (isActivityIntent || canBubble) {
mAssistManagerLazy.get().hideAssist();
}
if (shouldCollapse()) {
collapseOnMainThread();
}
NotificationVisibility.NotificationLocation location =
NotificationLogger.getNotificationLocation(entry);
@@ -408,6 +405,12 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
mMainThreadHandler.post(
() -> mBubblesManagerOptional.get().expandStackAndSelectBubble(entry));
}
// expandStackAndSelectBubble won't affect shouldCollapse, so we can collapse directly even
// if we are not on the main thread.
if (shouldCollapse()) {
collapseOnMainThread();
}
}
private void startNotificationIntent(
@@ -438,6 +441,9 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
null, null, options);
mMainThreadHandler.post(() -> {
mActivityLaunchAnimator.setLaunchResult(launchResult, isActivityIntent);
if (shouldCollapse()) {
collapseOnMainThread();
}
});
} catch (RemoteException | PendingIntent.CanceledException e) {
// the stack trace isn't very helpful here.
@@ -465,11 +471,11 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
mActivityLaunchAnimator.setLaunchResult(launchResult,
true /* isActivityIntent */);
removeHUN(row);
if (shouldCollapse()) {
mCommandQueue.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
true /* force */);
}
});
if (shouldCollapse()) {
mMainThreadHandler.post(() -> mCommandQueue.animateCollapsePanels(
CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */));
}
});
return true;
}, null, false /* afterKeyguardGone */);