Merge "Improved the behavior of overscroll" into sc-dev

This commit is contained in:
Selim Cinek
2021-06-07 18:12:40 +00:00
committed by Android (Google) Code Review
11 changed files with 220 additions and 153 deletions

View File

@@ -311,6 +311,13 @@ public class FlingAnimationUtils {
return mMinVelocityPxPerSecond;
}
/**
* @return a velocity considered fast
*/
public float getHighVelocityPxPerSecond() {
return mHighVelocityPxPerSecond;
}
/**
* An interpolator which interpolates two interpolators with an interpolator.
*/

View File

@@ -93,6 +93,16 @@ public class Interpolators {
(float) (1.0f - Math.exp(-b * progress)) * (overshootAmount + 1.0f));
}
/**
* Similar to {@link #getOvershootInterpolation(float, float, float)} but the overshoot
* starts immediately here, instead of first having a section of non-overshooting
*
* @param progress a progress value going from 0 to 1
*/
public static float getOvershootInterpolation(float progress) {
return MathUtils.max(0.0f, (float) (1.0f - Math.exp(-4 * progress)));
}
/**
* Interpolate alpha for notifications background scrim during shade expansion.
* @param fraction Shade expansion fraction

View File

@@ -771,6 +771,9 @@
<!-- Move distance for the unlock hint animation on the lockscreen -->
<dimen name="hint_move_distance">75dp</dimen>
<!-- The overshoot amount when the panel flings open -->
<dimen name="panel_overshoot_amount">16dp</dimen>
<!-- The width of the region on the left/right edge of the screen for performing the camera/
phone hints. -->
<dimen name="edge_tap_area_width">48dp</dimen>

View File

@@ -83,7 +83,7 @@ public class AmbientState {
private ExpandableNotificationRow mTrackedHeadsUpRow;
private float mAppearFraction;
private boolean mIsShadeOpening;
private float mSectionPadding;
private float mOverExpansion;
/** Distance of top of notifications panel from top of screen. */
private float mStackY = 0;
@@ -182,12 +182,12 @@ public class AmbientState {
return mIsShadeOpening;
}
void setSectionPadding(float padding) {
mSectionPadding = padding;
void setOverExpansion(float overExpansion) {
mOverExpansion = overExpansion;
}
float getSectionPadding() {
return mSectionPadding;
float getOverExpansion() {
return mOverExpansion;
}
private static int getZDistanceBetweenElements(Context context) {

View File

@@ -119,6 +119,7 @@ import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import javax.inject.Inject;
import javax.inject.Named;
@@ -470,6 +471,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
};
private Consumer<Integer> mScrollListener;
private final ScrollAdapter mScrollAdapter = new ScrollAdapter() {
@Override
public boolean isScrolledToTop() {
@@ -552,8 +554,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
}
void setSectionPadding(float margin) {
mAmbientState.setSectionPadding(margin);
/**
* Set the overexpansion of the panel to be applied to the view.
*/
void setOverExpansion(float margin) {
mAmbientState.setOverExpansion(margin);
updateStackPosition();
requestChildrenUpdate();
}
@@ -1136,7 +1142,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
*/
private void updateStackPosition() {
// Consider interpolating from an mExpansionStartY for use on lockscreen and AOD
float endTopPosition = mTopPadding + mExtraTopInsetForFullShadeTransition;
float endTopPosition = mTopPadding + mExtraTopInsetForFullShadeTransition
+ mAmbientState.getOverExpansion();
final float fraction = mAmbientState.getExpansionFraction();
final float stackY = MathUtils.lerp(0, endTopPosition, fraction);
mAmbientState.setStackY(stackY);
@@ -1144,7 +1151,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mOnStackYChanged.run();
}
if (mQsExpansionFraction <= 0) {
final float scrimTopPadding = mAmbientState.isOnKeyguard() ? 0 : mSidePaddings;
final float stackEndHeight = Math.max(0f,
getHeight() - getEmptyBottomMargin() - mTopPadding);
mAmbientState.setStackEndHeight(stackEndHeight);
@@ -1166,7 +1172,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
public void setExpandedHeight(float height) {
final float shadeBottom = getHeight() - getEmptyBottomMargin();
final float expansionFraction = MathUtils.constrain(height / shadeBottom, 0f, 1f);
final float expansionFraction = MathUtils.saturate(height / shadeBottom);
mAmbientState.setExpansionFraction(expansionFraction);
updateStackPosition();
@@ -2395,8 +2401,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
float topOverScroll = getCurrentOverScrollAmount(true);
return mScrolledToTopOnFirstDown
&& !mExpandedInThisMotion
&& topOverScroll > mMinTopOverScrollToEscape
&& initialVelocity > 0;
&& (initialVelocity > mMinimumVelocity
|| (topOverScroll > mMinTopOverScrollToEscape && initialVelocity > 0));
}
/**
@@ -4552,6 +4558,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
private void updateOnScrollChange() {
if (mScrollListener != null) {
mScrollListener.accept(mOwnScrollY);
}
updateForwardAndBackwardScrollability();
requestChildrenUpdate();
}
@@ -5162,6 +5171,13 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
requestChildrenUpdate();
}
/**
* Set a listener to when scrolling changes.
*/
public void setOnScrollListener(Consumer<Integer> listener) {
mScrollListener = listener;
}
/**
* A listener that is notified when the empty space below the notifications is clicked on
*/

View File

@@ -124,6 +124,7 @@ import com.android.systemui.tuner.TunerService;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import javax.inject.Inject;
import javax.inject.Named;
@@ -302,8 +303,11 @@ public class NotificationStackScrollLayoutController {
}
};
public void setSectionPadding(float padding) {
mView.setSectionPadding(padding);
/**
* Set the overexpansion of the panel to be applied to the view.
*/
public void setOverExpansion(float overExpansion) {
mView.setOverExpansion(overExpansion);
}
private final OnMenuEventListener mMenuEventListener = new OnMenuEventListener() {
@@ -944,10 +948,6 @@ public class NotificationStackScrollLayoutController {
mView.setOverScrollAmount(amount, onTop, animate);
}
public void setOverScrolledPixels(float numPixels, boolean onTop, boolean animate) {
mView.setOverScrolledPixels(numPixels, onTop, animate);
}
public void resetScrollPosition() {
mView.resetScrollPosition();
}
@@ -1054,10 +1054,6 @@ public class NotificationStackScrollLayoutController {
return mView.getCurrentOverScrollAmount(top);
}
public float getCurrentOverScrolledPixels(boolean top) {
return mView.getCurrentOverScrolledPixels(top);
}
public float calculateAppearFraction(float height) {
return mView.calculateAppearFraction(height);
}
@@ -1430,6 +1426,13 @@ public class NotificationStackScrollLayoutController {
mView.setExtraTopInsetForFullShadeTransition(extraTopInset);
}
/**
* Set a listener to when scrolling changes.
*/
public void setOnScrollListener(Consumer<Integer> listener) {
mView.setOnScrollListener(listener);
}
/**
* Enum for UiEvent logged from this class
*/

View File

@@ -403,10 +403,6 @@ public class StackScrollAlgorithm {
}
viewState.yTranslation = algorithmState.mCurrentYPosition;
if (view instanceof SectionHeaderView) {
// Add padding before sections for overscroll effect.
viewState.yTranslation += expansionFraction * ambientState.getSectionPadding();
}
if (view instanceof FooterView) {
final boolean shadeClosed = !ambientState.isShadeExpanded();

View File

@@ -510,7 +510,6 @@ public class NotificationPanelViewController extends PanelViewController {
private boolean mShowingKeyguardHeadsUp;
private boolean mAllowExpandForSmallExpansion;
private Runnable mExpandAfterLayoutRunnable;
private float mSectionPadding;
/**
* The padding between the start of notifications and the qs boundary on the lockscreen.
@@ -589,7 +588,6 @@ public class NotificationPanelViewController extends PanelViewController {
private NotificationShelfController mNotificationShelfController;
private int mScrimCornerRadius;
private int mScreenCornerRadius;
private int mNotificationScrimPadding;
private boolean mQSAnimatingHiddenFromCollapsed;
private final Executor mUiExecutor;
@@ -824,6 +822,7 @@ public class NotificationPanelViewController extends PanelViewController {
mOnHeightChangedListener);
mNotificationStackScrollLayoutController.setOverscrollTopChangedListener(
mOnOverscrollTopChangedListener);
mNotificationStackScrollLayoutController.setOnScrollListener(this::onNotificationScrolled);
mNotificationStackScrollLayoutController.setOnEmptySpaceClickListener(
mOnEmptySpaceClickListener);
addTrackingHeadsUpListener(mNotificationStackScrollLayoutController::setTrackingHeadsUp);
@@ -908,8 +907,6 @@ public class NotificationPanelViewController extends PanelViewController {
mScrimCornerRadius = mResources.getDimensionPixelSize(
R.dimen.notification_scrim_corner_radius);
mScreenCornerRadius = (int) ScreenDecorationsUtils.getWindowCornerRadius(mResources);
mNotificationScrimPadding = mResources.getDimensionPixelSize(
R.dimen.notification_side_paddings);
mLockscreenNotificationQSPadding = mResources.getDimensionPixelSize(
R.dimen.notification_side_paddings);
}
@@ -2190,6 +2187,22 @@ public class NotificationPanelViewController extends PanelViewController {
}
};
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
updateQSExpansionEnabled();
}
@Override
public void setIsShadeOpening(boolean opening) {
mAmbientState.setIsShadeOpening(opening);
updateQSExpansionEnabled();
}
private void updateQSExpansionEnabled() {
setQsExpansionEnabled(mAmbientState.getScrollY() <= 0 && !mAmbientState.isShadeOpening());
}
/**
* Updates scrim bounds, QS clipping, and KSV clipping as well based on the bounds of the shade
* and QS state.
@@ -2203,7 +2216,6 @@ public class NotificationPanelViewController extends PanelViewController {
final int qsPanelBottomY = calculateQsBottomPosition(computeQsExpansionFraction());
final boolean visible = (computeQsExpansionFraction() > 0 || qsPanelBottomY > 0)
&& !mShouldUseSplitNotificationShade;
setQsExpansionEnabled(mAmbientState.getScrollY() == 0 && !mAmbientState.isShadeOpening());
if (!mShouldUseSplitNotificationShade) {
if (mTransitioningToFullShadeProgress > 0.0f) {
@@ -2315,8 +2327,6 @@ public class NotificationPanelViewController extends PanelViewController {
qsBottomY = (int) MathUtils.lerp(
qsBottomY, mQs.getDesiredHeight(), qsExpansionFraction);
}
// to account for shade overshooting animation, see setSectionPadding method
if (mSectionPadding > 0) qsBottomY += mSectionPadding;
return qsBottomY;
}
}
@@ -2632,7 +2642,7 @@ public class NotificationPanelViewController extends PanelViewController {
int min = mStatusBarMinHeight;
if (!(mBarState == KEYGUARD)
&& mNotificationStackScrollLayoutController.getNotGoneChildCount() == 0) {
int minHeight = (int) (mQsMinExpansionHeight + getOverExpansionAmount());
int minHeight = mQsMinExpansionHeight;
min = Math.max(min, minHeight);
}
int maxHeight;
@@ -2644,8 +2654,8 @@ public class NotificationPanelViewController extends PanelViewController {
}
maxHeight = Math.max(min, maxHeight);
if (maxHeight == 0 || isNaN(maxHeight)) {
Log.wtf(TAG, "maxPanelHeight is invalid. getOverExpansionAmount(): "
+ getOverExpansionAmount() + ", calculatePanelHeightQsExpanded: "
Log.wtf(TAG, "maxPanelHeight is invalid. mOverExpansion: "
+ mOverExpansion + ", calculatePanelHeightQsExpanded: "
+ calculatePanelHeightQsExpanded() + ", calculatePanelHeightShade: "
+ calculatePanelHeightShade() + ", mStatusBarMinHeight = "
+ mStatusBarMinHeight + ", mQsMinExpansionHeight = " + mQsMinExpansionHeight);
@@ -2807,23 +2817,6 @@ public class NotificationPanelViewController extends PanelViewController {
return alpha;
}
@Override
protected float getOverExpansionAmount() {
float result = mNotificationStackScrollLayoutController
.getCurrentOverScrollAmount(true /* top */);
if (isNaN(result)) {
Log.wtf(TAG, "OverExpansionAmount is NaN!");
}
return result;
}
@Override
protected float getOverExpansionPixels() {
return mNotificationStackScrollLayoutController
.getCurrentOverScrolledPixels(true /* top */);
}
/**
* Hides the header when notifications are colliding with it.
*/
@@ -3018,31 +3011,15 @@ public class NotificationPanelViewController extends PanelViewController {
}
@Override
public void setSectionPadding(float padding) {
if (padding == mSectionPadding) {
public void setOverExpansion(float overExpansion) {
if (overExpansion == mOverExpansion) {
return;
}
mSectionPadding = padding;
// TODO(b/172289889) update overscroll to spec
}
@Override
protected void setOverExpansion(float overExpansion, boolean isPixels) {
if (mConflictingQsExpansionGesture || mQsExpandImmediate) {
return;
}
if (mBarState != KEYGUARD) {
mNotificationStackScrollLayoutController.setOnHeightChangedListener(null);
if (isPixels) {
mNotificationStackScrollLayoutController.setOverScrolledPixels(
overExpansion, true /* onTop */, false /* animate */);
} else {
mNotificationStackScrollLayoutController.setOverScrollAmount(
overExpansion, true /* onTop */, false /* animate */);
}
mNotificationStackScrollLayoutController
.setOnHeightChangedListener(mOnHeightChangedListener);
}
super.setOverExpansion(overExpansion);
// Translating the quick settings by half the overexpansion to center it in the background
// frame
mQsFrame.setTranslationY(overExpansion / 2f);
mNotificationStackScrollLayoutController.setOverExpansion(overExpansion);
}
@Override
@@ -3066,7 +3043,7 @@ public class NotificationPanelViewController extends PanelViewController {
mFalsingCollector.onTrackingStopped();
super.onTrackingStopped(expand);
if (expand) {
mNotificationStackScrollLayoutController.setOverScrolledPixels(0.0f, true /* onTop */,
mNotificationStackScrollLayoutController.setOverScrollAmount(0.0f, true /* onTop */,
true /* animate */);
}
mNotificationStackScrollLayoutController.onPanelTrackingStopped();
@@ -3111,18 +3088,6 @@ public class NotificationPanelViewController extends PanelViewController {
|| !isTracking());
}
@Override
protected boolean fullyExpandedClearAllVisible() {
return mNotificationStackScrollLayoutController.isFooterViewNotGone()
&& mNotificationStackScrollLayoutController.isScrolledToBottom()
&& !mQsExpandImmediate;
}
@Override
protected boolean isClearAllVisible() {
return mNotificationStackScrollLayoutController.isFooterViewContentVisible();
}
@Override
protected boolean isTrackingBlocked() {
return mConflictingQsExpansionGesture && mQsExpanded || mBlockingExpansionForCurrentTouch;
@@ -3973,10 +3938,15 @@ public class NotificationPanelViewController extends PanelViewController {
}
mLastOverscroll = 0f;
mQsExpansionFromOverscroll = false;
if (open) {
// During overscrolling, qsExpansion doesn't actually change that the qs is
// becoming expanded. Any layout could therefore reset the position again. Let's
// make sure we can expand
setOverScrolling(false);
}
setQsExpansion(mQsExpansionHeight);
flingSettings(!mQsExpansionEnabled && open ? 0f : velocity,
open && mQsExpansionEnabled ? FLING_EXPAND : FLING_COLLAPSE, () -> {
mStackScrollerOverscrolling = false;
setOverScrolling(false);
updateQsState();
}, false /* isClick */);
@@ -4392,7 +4362,7 @@ public class NotificationPanelViewController extends PanelViewController {
if (mQsMaxExpansionHeight != oldMaxHeight) {
startQsSizeChangeAnimation(oldMaxHeight, mQsMaxExpansionHeight);
}
} else if (!mQsExpanded) {
} else if (!mQsExpanded && mQsExpansionAnimator == null) {
setQsExpansion(mQsMinExpansionHeight + mLastOverscroll);
}
updateExpandedHeight(getExpandedHeight());

View File

@@ -53,7 +53,7 @@ public abstract class PanelBar extends FrameLayout {
if (DEBUG) LOG("go state: %d -> %d", mState, state);
mState = state;
if (mPanel != null) {
mPanel.getAmbientState().setIsShadeOpening(state == STATE_OPENING);
mPanel.setIsShadeOpening(state == STATE_OPENING);
}
}

View File

@@ -68,12 +68,14 @@ public abstract class PanelViewController {
public static final String TAG = PanelView.class.getSimpleName();
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 static final long SHADE_OPEN_SPRING_BACK_DURATION = 400L;
/**
* The factor of the usual high velocity that is needed in order to reach the maximum overshoot
* when flinging. A low value will make it that most flings will reach the maximum overshoot.
*/
private static final float FACTOR_OF_HIGH_VELOCITY_FOR_MAX_OVERSHOOT = 0.5f;
private float mFlingTarget;
private float mFlingVelocity;
protected long mDownTime;
protected boolean mTouchSlopExceededBeforeDown;
private float mMinExpandHeight;
@@ -83,6 +85,22 @@ public abstract class PanelViewController {
protected boolean mIsLaunchAnimationRunning;
private int mFixedDuration = NO_FIXED_DURATION;
protected ArrayList<PanelExpansionListener> mExpansionListeners = new ArrayList<>();
protected float mOverExpansion;
/**
* The overshoot amount when the panel flings open
*/
private float mPanelFlingOvershootAmount;
/**
* The amount of pixels that we have overexpanded the last time with a gesture
*/
private float mLastGesturedOverExpansion = -1;
/**
* Is the current animator the spring back animation?
*/
private boolean mIsSpringBackAnimation;
private void logf(String fmt, Object... args) {
Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
@@ -254,6 +272,7 @@ public abstract class PanelViewController {
mTouchSlop = configuration.getScaledTouchSlop();
mSlopMultiplier = configuration.getScaledAmbiguousGestureMultiplier();
mHintDistance = mResources.getDimension(R.dimen.hint_move_distance);
mPanelFlingOvershootAmount = mResources.getDimension(R.dimen.panel_overshoot_amount);
mUnlockFalsingThreshold = mResources.getDimensionPixelSize(
R.dimen.unlock_falsing_threshold);
}
@@ -529,21 +548,38 @@ public abstract class PanelViewController {
protected void flingToHeight(float vel, boolean expand, float target,
float collapseSpeedUpFactor, boolean expandBecauseOfFalsing) {
if (target == mExpandedHeight || getOverExpansionAmount() > 0f && expand) {
if (target == mExpandedHeight && mOverExpansion == 0.0f) {
// We're at the target and didn't fling and there's no overshoot
endJankMonitoring(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
mKeyguardStateController.notifyPanelFlingEnd();
notifyExpandingFinished();
return;
}
mIsFlinging = true;
mOverExpandedBeforeFling = getOverExpansionAmount() > 0f;
ValueAnimator animator = createHeightAnimator(target);
mFlingTarget = target;
// we want to perform an overshoot animation when flinging open
final boolean addOverscroll = expand
&& mStatusBarStateController.getState() != StatusBarState.KEYGUARD
&& mOverExpansion == 0.0f
&& vel >= 0;
final boolean shouldSpringBack = addOverscroll || (mOverExpansion != 0.0f && expand);
float overshootAmount = 0.0f;
if (addOverscroll) {
// Let's overshoot depending on the amount of velocity
overshootAmount = MathUtils.lerp(
0.2f,
1.0f,
MathUtils.saturate(vel
/ (mFlingAnimationUtils.getHighVelocityPxPerSecond()
* FACTOR_OF_HIGH_VELOCITY_FOR_MAX_OVERSHOOT)));
overshootAmount += mOverExpansion / mPanelFlingOvershootAmount;
}
ValueAnimator animator = createHeightAnimator(target, overshootAmount);
if (expand) {
if (expandBecauseOfFalsing && vel < 0) {
vel = 0;
}
mFlingAnimationUtils.apply(animator, mExpandedHeight, target, vel, mView.getHeight());
mFlingAnimationUtils.apply(animator, mExpandedHeight,
target + overshootAmount * mPanelFlingOvershootAmount, vel, mView.getHeight());
if (vel == 0) {
animator.setDuration(SHADE_OPEN_SPRING_OUT_DURATION);
}
@@ -570,7 +606,6 @@ public abstract class PanelViewController {
animator.setDuration(mFixedDuration);
}
}
mFlingVelocity = vel;
animator.addListener(new AnimatorListenerAdapter() {
private boolean mCancelled;
@@ -586,7 +621,7 @@ public abstract class PanelViewController {
@Override
public void onAnimationEnd(Animator animation) {
if (expand && mFlingVelocity > 0) {
if (shouldSpringBack && !mCancelled) {
// After the shade is flinged open to an overscrolled state, spring back
// the shade by reducing section padding to 0.
springBack();
@@ -600,14 +635,19 @@ public abstract class PanelViewController {
}
private void springBack() {
ValueAnimator animator = ValueAnimator.ofFloat(MAX_OVERSCROLL, 0);
if (mOverExpansion == 0) {
onFlingEnd(false /* cancelled */);
return;
}
mIsSpringBackAnimation = true;
ValueAnimator animator = ValueAnimator.ofFloat(mOverExpansion, 0);
animator.addUpdateListener(
animation -> {
setSectionPadding((float) animation.getAnimatedValue());
setExpandedHeightInternal(mFlingTarget);
setOverExpansionInternal((float) animation.getAnimatedValue(),
false /* isFromGesture */);
});
animator.setDuration(SHADE_OPEN_SPRING_BACK_DURATION);
animator.setInterpolator(Interpolators.LINEAR);
animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
animator.addListener(new AnimatorListenerAdapter() {
private boolean mCancelled;
@Override
@@ -616,6 +656,7 @@ public abstract class PanelViewController {
}
@Override
public void onAnimationEnd(Animator animation) {
mIsSpringBackAnimation = false;
onFlingEnd(mCancelled);
}
});
@@ -625,6 +666,8 @@ public abstract class PanelViewController {
private void onFlingEnd(boolean cancelled) {
mIsFlinging = false;
// No overshoot when the animation ends
setOverExpansionInternal(0, false /* isFromGesture */);
setAnimator(null);
mKeyguardStateController.notifyPanelFlingEnd();
if (!cancelled) {
@@ -644,7 +687,7 @@ public abstract class PanelViewController {
public void setExpandedHeight(float height) {
if (DEBUG) logf("setExpandedHeight(%.1f)", height);
setExpandedHeightInternal(height + getOverExpansionPixels());
setExpandedHeightInternal(height);
}
protected void requestPanelHeightUpdate() {
@@ -662,7 +705,7 @@ public abstract class PanelViewController {
return;
}
if (mHeightAnimator != null) {
if (mHeightAnimator != null && !mIsSpringBackAnimation) {
mPanelUpdateWhenAnimatorEnds = true;
return;
}
@@ -677,38 +720,24 @@ public abstract class PanelViewController {
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));
mExpandLatencyTracking = false;
}
float fhWithoutOverExpansion = getMaxPanelHeight() - getOverExpansionAmount();
float maxPanelHeight = getMaxPanelHeight();
if (mHeightAnimator == null) {
float overExpansionPixels = Math.max(0, h - fhWithoutOverExpansion);
if (getOverExpansionPixels() != overExpansionPixels && mTracking) {
setOverExpansion(overExpansionPixels, true /* isPixels */);
if (mTracking) {
float overExpansionPixels = Math.max(0, h - maxPanelHeight);
setOverExpansionInternal(overExpansionPixels, true /* isFromGesture */);
}
mExpandedHeight = Math.min(h, fhWithoutOverExpansion) + getOverExpansionAmount();
mExpandedHeight = Math.min(h, maxPanelHeight);
} else {
mExpandedHeight = h;
if (mOverExpandedBeforeFling) {
setOverExpansion(Math.max(0, h - fhWithoutOverExpansion), false /* isPixels */);
}
}
// If we are closing the panel and we are almost there due to a slow decelerating
@@ -720,7 +749,7 @@ public abstract class PanelViewController {
}
}
mExpandedFraction = Math.min(1f,
fhWithoutOverExpansion == 0 ? 0 : mExpandedHeight / fhWithoutOverExpansion);
maxPanelHeight == 0 ? 0 : mExpandedHeight / maxPanelHeight);
onHeightUpdated(mExpandedHeight);
notifyBarPanelExpansionChanged();
}
@@ -731,16 +760,31 @@ public abstract class PanelViewController {
*/
protected abstract boolean isTrackingBlocked();
protected abstract void setSectionPadding(float padding);
protected void setOverExpansion(float overExpansion) {
mOverExpansion = overExpansion;
}
protected abstract void setOverExpansion(float overExpansion, boolean isPixels);
/**
* Set the current overexpansion
*
* @param overExpansion the amount of overexpansion to apply
* @param isFromGesture is this amount from a gesture and needs to be rubberBanded?
*/
private void setOverExpansionInternal(float overExpansion, boolean isFromGesture) {
if (!isFromGesture) {
mLastGesturedOverExpansion = -1;
setOverExpansion(overExpansion);
} else if (mLastGesturedOverExpansion != overExpansion) {
mLastGesturedOverExpansion = overExpansion;
final float heightForFullOvershoot = mView.getHeight() / 3.0f;
float newExpansion = MathUtils.saturate(overExpansion / heightForFullOvershoot);
newExpansion = Interpolators.getOvershootInterpolation(newExpansion);
setOverExpansion(newExpansion * mPanelFlingOvershootAmount * 2.0f);
}
}
protected abstract void onHeightUpdated(float expandedHeight);
protected abstract float getOverExpansionAmount();
protected abstract float getOverExpansionPixels();
/**
* This returns the maximum height of the panel. Children should override this if their
* desired height is not the full height.
@@ -977,9 +1021,32 @@ public abstract class PanelViewController {
}
private ValueAnimator createHeightAnimator(float targetHeight) {
return createHeightAnimator(targetHeight, 0.0f /* performOvershoot */);
}
/**
* Create an animator that can also overshoot
*
* @param targetHeight the target height
* @param overshootAmount the amount of overshoot desired
*/
private ValueAnimator createHeightAnimator(float targetHeight, float overshootAmount) {
float startExpansion = mOverExpansion;
ValueAnimator animator = ValueAnimator.ofFloat(mExpandedHeight, targetHeight);
animator.addUpdateListener(
animation -> setExpandedHeightInternal((float) animation.getAnimatedValue()));
animation -> {
if (overshootAmount > 0.0f
// Also remove the overExpansion when collapsing
|| (targetHeight == 0.0f && startExpansion != 0)) {
final float expansion = MathUtils.lerp(
startExpansion,
mPanelFlingOvershootAmount * overshootAmount,
Interpolators.FAST_OUT_SLOW_IN.getInterpolation(
animator.getAnimatedFraction()));
setOverExpansionInternal(expansion, false /* isFromGesture */);
}
setExpandedHeightInternal((float) animation.getAnimatedValue());
});
return animator;
}
@@ -989,7 +1056,7 @@ public abstract class PanelViewController {
mExpandedFraction,
mExpandedFraction > 0f || mInstantExpanding
|| isPanelVisibleBecauseOfHeadsUp() || mTracking
|| mHeightAnimator != null);
|| mHeightAnimator != null && !mIsSpringBackAnimation);
}
for (int i = 0; i < mExpansionListeners.size(); i++) {
mExpansionListeners.get(i).onPanelExpansionChanged(mExpandedFraction, mTracking);
@@ -1037,14 +1104,6 @@ public abstract class PanelViewController {
public abstract void resetViews(boolean animate);
/**
* @return whether "Clear all" button will be visible when the panel is fully expanded
*/
protected abstract boolean fullyExpandedClearAllVisible();
protected abstract boolean isClearAllVisible();
public void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) {
mHeadsUpManager = headsUpManager;
}
@@ -1080,6 +1139,11 @@ public abstract class PanelViewController {
return new OnConfigurationChangedListener();
}
/**
* Set that the panel is currently opening and not fully opened or closed.
*/
public abstract void setIsShadeOpening(boolean opening);
public class TouchHandler implements View.OnTouchListener {
public boolean onInterceptTouchEvent(MotionEvent event) {
if (mInstantExpanding || !mNotificationsDragEnabled || mTouchDisabled || (mMotionAborted
@@ -1108,7 +1172,7 @@ public abstract class PanelViewController {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
mStatusBar.userActivity();
mAnimatingOnDown = mHeightAnimator != null;
mAnimatingOnDown = mHeightAnimator != null && !mIsSpringBackAnimation;
mMinExpandHeight = 0.0f;
mDownTime = SystemClock.uptimeMillis();
if (mAnimatingOnDown && mClosing && !mHintAnimationRunning) {
@@ -1227,10 +1291,10 @@ public abstract class PanelViewController {
mCollapsedAndHeadsUpOnDown =
isFullyCollapsed() && mHeadsUpManager.hasPinnedHeadsUp();
addMovement(event);
if (!mGestureWaitForTouchSlop || (mHeightAnimator != null
&& !mHintAnimationRunning)) {
mTouchSlopExceeded =
(mHeightAnimator != null && !mHintAnimationRunning)
boolean regularHeightAnimationRunning = mHeightAnimator != null
&& !mHintAnimationRunning && !mIsSpringBackAnimation;
if (!mGestureWaitForTouchSlop || regularHeightAnimationRunning) {
mTouchSlopExceeded = regularHeightAnimationRunning
|| mTouchSlopExceededBeforeDown;
cancelHeightAnimator();
onTrackingStarted();

View File

@@ -638,8 +638,6 @@ public class NotificationPanelViewTest extends SysuiTestCase {
public void testCancelSwipeWhileLocked_notifiesKeyguardState() {
mStatusBarStateController.setState(KEYGUARD);
mNotificationPanelViewController.setOverExpansion(100f, true);
// Fling expanded (cancelling the keyguard exit swipe). We should notify keyguard state that
// the fling occurred and did not dismiss the keyguard.
mNotificationPanelViewController.flingToHeight(