Fling shade open with overscroll
By adding space before sections. - Propagate section padding from PVC to AmbientState. - NPVC translates QSFrame down by section padding - StackScrollAlgorithm adds section padding above section headers Bug: 172289889 Test: visual Change-Id: I7cb1438fbe83b4e82c95ea8b3a471c7f6adfcaf1
This commit is contained in:
@@ -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));
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -475,6 +475,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
|
||||
@@ -2412,6 +2413,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) {
|
||||
@@ -2498,19 +2509,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()
|
||||
@@ -2529,11 +2527,6 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
return mNotificationStackScrollLayoutController.isFooterViewContentVisible();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getClearAllHeightWithPadding() {
|
||||
return mNotificationStackScrollLayoutController.getFooterViewHeightWithPadding();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isTrackingBlocked() {
|
||||
return mConflictingQsExpansionGesture && mQsExpanded || mBlockingExpansionForCurrentTouch;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user