Merge "Fling shade open with overscroll"

This commit is contained in:
Lyn Han
2021-01-20 21:41:23 +00:00
committed by Android (Google) Code Review
7 changed files with 110 additions and 57 deletions

View File

@@ -78,6 +78,7 @@ public class AmbientState {
private ExpandableNotificationRow mTrackedHeadsUpRow;
private float mAppearFraction;
private boolean mIsShadeOpening;
private float mSectionPadding;
/** Tracks the state from AlertingNotificationManager#hasNotifications() */
private boolean mHasAlertEntries;
@@ -105,6 +106,14 @@ public class AmbientState {
return mIsShadeOpening;
}
void setSectionPadding(float padding) {
mSectionPadding = padding;
}
float getSectionPadding() {
return mSectionPadding;
}
private static int getZDistanceBetweenElements(Context context) {
return Math.max(1, context.getResources()
.getDimensionPixelSize(R.dimen.z_distance_between_notifications));

View File

@@ -554,6 +554,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mAmbientState.setIsShadeOpening(isOpening);
}
void setSectionPadding(float margin) {
mAmbientState.setSectionPadding(margin);
requestChildrenUpdate();
}
@Override
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
protected void onFinishInflate() {

View File

@@ -275,6 +275,10 @@ public class NotificationStackScrollLayoutController {
mView.setIsShadeOpening(isOpening);
}
public void setSectionPadding(float padding) {
mView.setSectionPadding(padding);
}
private final OnMenuEventListener mMenuEventListener = new OnMenuEventListener() {
@Override
public void onMenuClicked(

View File

@@ -341,7 +341,8 @@ public class StackScrollAlgorithm {
boolean isEmptyShadeView = child instanceof EmptyShadeView;
childViewState.location = ExpandableViewState.LOCATION_MAIN_AREA;
float inset = ambientState.getTopPadding() + ambientState.getStackTranslation();
float inset = ambientState.getTopPadding() + ambientState.getStackTranslation()
+ ambientState.getSectionPadding();
if (i <= algorithmState.getIndexOfExpandingNotification()) {
inset += ambientState.getExpandAnimationTopChange();
}
@@ -563,6 +564,10 @@ public class StackScrollAlgorithm {
childViewState.yTranslation = Math.max(childViewState.yTranslation, shelfStart);
}
childViewState.yTranslation = Math.min(childViewState.yTranslation, shelfStart);
if (child instanceof SectionHeaderView) {
// Add padding before sections for overscroll effect.
childViewState.yTranslation += ambientState.getSectionPadding();
}
if (childViewState.yTranslation >= shelfStart) {
childViewState.hidden = !child.isExpandAnimationRunning() && !child.hasExpandingChild();
childViewState.inShelf = true;

View File

@@ -477,6 +477,7 @@ public class NotificationPanelViewController extends PanelViewController {
private boolean mShowingKeyguardHeadsUp;
private boolean mAllowExpandForSmallExpansion;
private Runnable mExpandAfterLayoutRunnable;
private float mSectionPadding;
/**
* Is this a collapse that started on the panel where we should allow the panel to intercept
@@ -2415,6 +2416,16 @@ public class NotificationPanelViewController extends PanelViewController {
mNotificationStackScrollLayoutController.setIsShadeOpening(isOpening);
}
@Override
public void setSectionPadding(float padding) {
if (padding == mSectionPadding) {
return;
}
mSectionPadding = padding;
mQsFrame.setTranslationY(padding);
mNotificationStackScrollLayoutController.setSectionPadding(padding);
}
@Override
protected void setOverExpansion(float overExpansion, boolean isPixels) {
if (mConflictingQsExpansionGesture || mQsExpandImmediate) {
@@ -2501,19 +2512,6 @@ public class NotificationPanelViewController extends PanelViewController {
}
}
@Override
protected boolean shouldExpandToTopOfClearAll(float targetHeight) {
boolean perform = super.shouldExpandToTopOfClearAll(targetHeight);
if (!perform) {
return false;
}
// Let's make sure we're not appearing but the animation will end below the appear.
// Otherwise quick settings would jump at the end of the animation.
float fraction = mNotificationStackScrollLayoutController
.calculateAppearFraction(targetHeight);
return fraction >= 1.0f;
}
@Override
protected boolean shouldUseDismissingAnimation() {
return mBarState != StatusBarState.SHADE && (mKeyguardStateController.canDismissLockScreen()
@@ -2532,11 +2530,6 @@ public class NotificationPanelViewController extends PanelViewController {
return mNotificationStackScrollLayoutController.isFooterViewContentVisible();
}
@Override
protected int getClearAllHeightWithPadding() {
return mNotificationStackScrollLayoutController.getFooterViewHeightWithPadding();
}
@Override
protected boolean isTrackingBlocked() {
return mConflictingQsExpansionGesture && mQsExpanded || mBlockingExpansionForCurrentTouch;

View File

@@ -57,6 +57,10 @@ public abstract class PanelBar extends FrameLayout {
}
}
protected boolean isShadeOpening() {
return mState == STATE_OPENING;
}
@Override
protected Parcelable onSaveInstanceState() {
Bundle bundle = new Bundle();

View File

@@ -32,6 +32,7 @@ import android.content.res.Resources;
import android.os.SystemClock;
import android.os.VibrationEffect;
import android.util.Log;
import android.util.MathUtils;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.VelocityTracker;
@@ -67,6 +68,13 @@ public abstract class PanelViewController {
private static final int INITIAL_OPENING_PEEK_DURATION = 200;
private static final int PEEK_ANIMATION_DURATION = 360;
private static final int NO_FIXED_DURATION = -1;
private static final long SHADE_OPEN_SPRING_OUT_DURATION = 350L;
private static final long SHADE_OPEN_SPRING_BACK_DURATION = 200L;
private static final float MIN_OVERSCROLL = -50;
private static final float MAX_OVERSCROLL = 30;
private float mFlingTarget;
private float mFlingVelocity;
protected long mDownTime;
protected boolean mTouchSlopExceededBeforeDown;
private float mMinExpandHeight;
@@ -569,14 +577,6 @@ public abstract class PanelViewController {
protected void flingToHeight(float vel, boolean expand, float target,
float collapseSpeedUpFactor, boolean expandBecauseOfFalsing) {
// Hack to make the expand transition look nice when clear all button is visible - we make
// the animation only to the last notification, and then jump to the maximum panel height so
// clear all just fades in and the decelerating motion is towards the last notification.
final boolean clearAllExpandHack = expand &&
shouldExpandToTopOfClearAll(getMaxPanelHeight() - getClearAllHeightWithPadding());
if (clearAllExpandHack) {
target = getMaxPanelHeight() - getClearAllHeightWithPadding();
}
if (target == mExpandedHeight || getOverExpansionAmount() > 0f && expand) {
InteractionJankMonitor.getInstance().end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
notifyExpandingFinished();
@@ -584,13 +584,14 @@ public abstract class PanelViewController {
}
mOverExpandedBeforeFling = getOverExpansionAmount() > 0f;
ValueAnimator animator = createHeightAnimator(target);
mFlingTarget = target;
if (expand) {
if (expandBecauseOfFalsing && vel < 0) {
vel = 0;
}
mFlingAnimationUtils.apply(animator, mExpandedHeight, target, vel, mView.getHeight());
if (vel == 0) {
animator.setDuration(350);
animator.setDuration(SHADE_OPEN_SPRING_OUT_DURATION);
}
} else {
if (shouldUseDismissingAnimation()) {
@@ -615,6 +616,7 @@ public abstract class PanelViewController {
animator.setDuration(mFixedDuration);
}
}
mFlingVelocity = vel;
animator.addListener(new AnimatorListenerAdapter() {
private boolean mCancelled;
@@ -625,38 +627,54 @@ public abstract class PanelViewController {
@Override
public void onAnimationEnd(Animator animation) {
if (clearAllExpandHack && !mCancelled) {
setExpandedHeightInternal(getMaxPanelHeight());
}
setAnimator(null);
if (!mCancelled) {
InteractionJankMonitor.getInstance()
.end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
notifyExpandingFinished();
if (expand && mFlingVelocity > 0) {
// After the shade is flinged open to an overscrolled state, spring back
// the shade by reducing section padding to 0.
springBack();
} else {
InteractionJankMonitor.getInstance()
.cancel(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
onFlingEnd(mCancelled);
}
notifyBarPanelExpansionChanged();
}
});
setAnimator(animator);
animator.start();
}
/**
* When expanding, should we expand to the top of clear all and expand immediately?
* This will make sure that the animation will stop smoothly at the end of the last notification
* before the clear all affordance.
*
* @param targetHeight the height that we would animate to, right above clear all
*
* @return true if we can expand to the top of clear all
*/
protected boolean shouldExpandToTopOfClearAll(float targetHeight) {
return fullyExpandedClearAllVisible()
&& mExpandedHeight < targetHeight
&& !isClearAllVisible();
private void springBack() {
ValueAnimator animator = ValueAnimator.ofFloat(MAX_OVERSCROLL, 0);
animator.addUpdateListener(
animation -> {
setSectionPadding((float) animation.getAnimatedValue());
setExpandedHeightInternal(mFlingTarget);
});
animator.setDuration(SHADE_OPEN_SPRING_BACK_DURATION);
animator.setInterpolator(Interpolators.LINEAR);
animator.addListener(new AnimatorListenerAdapter() {
private boolean mCancelled;
@Override
public void onAnimationCancel(Animator animation) {
mCancelled = true;
}
@Override
public void onAnimationEnd(Animator animation) {
onFlingEnd(mCancelled);
}
});
setAnimator(animator);
animator.start();
}
private void onFlingEnd(boolean cancelled) {
setAnimator(null);
if (!cancelled) {
InteractionJankMonitor.getInstance()
.end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
notifyExpandingFinished();
} else {
InteractionJankMonitor.getInstance()
.cancel(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
}
notifyBarPanelExpansionChanged();
}
protected abstract boolean shouldUseDismissingAnimation();
@@ -697,10 +715,28 @@ public abstract class PanelViewController {
setExpandedHeight(currentMaxPanelHeight);
}
private float getStackHeightFraction(float height) {
final float gestureFraction = height / getMaxPanelHeight();
final float stackHeightFraction = Interpolators.ACCELERATE_DECELERATE
.getInterpolation(gestureFraction);
return stackHeightFraction;
}
// When the shade is flinged open, add space before sections for overscroll effect.
private void maybeOverScrollForShadeFlingOpen(float height) {
if (!mBar.isShadeOpening() || mFlingVelocity <= 0) {
return;
}
final float padding = MathUtils.lerp(
MIN_OVERSCROLL, MAX_OVERSCROLL, getStackHeightFraction(height));
setSectionPadding(padding);
}
public void setExpandedHeightInternal(float h) {
if (isNaN(h)) {
Log.wtf(TAG, "ExpandedHeight set to NaN");
}
maybeOverScrollForShadeFlingOpen(h);
if (mExpandLatencyTracking && h != 0f) {
DejankUtils.postAfterTraversal(
() -> mLatencyTracker.onActionEnd(LatencyTracker.ACTION_EXPAND_PANEL));
@@ -742,6 +778,8 @@ public abstract class PanelViewController {
protected abstract void setIsShadeOpening(boolean isShadeOpening);
protected abstract void setSectionPadding(float padding);
protected abstract void setOverExpansion(float overExpansion, boolean isPixels);
protected abstract void onHeightUpdated(float expandedHeight);
@@ -1075,11 +1113,6 @@ public abstract class PanelViewController {
protected abstract boolean isClearAllVisible();
/**
* @return the height of the clear all button, in pixels including padding
*/
protected abstract int getClearAllHeightWithPadding();
public void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) {
mHeadsUpManager = headsUpManager;
}