Merge "Improved the behavior of overscroll" into sc-dev
This commit is contained in:
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user