Improved the transition into the statusbar
When expanding, the shelf now transforms into
the statusbar, providing a more seemless transition.
This also modifies the panel peeking:
previously the panel was always peeking right after a tap timeout
which would take the panel away from the users finger.
The panel is now only peeking when the user clicked on the bar instead.
Test: Add some notification and collapse the panel. Observe nicer transition
Bug: 32437839
Change-Id: I772f6684e1cee2004e9b366d203a5c5188af4a93
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 081ed51..584d5c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -207,6 +207,7 @@
}
};
private NotificationGroupManager mGroupManager;
+ private boolean mOpening;
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -557,9 +558,7 @@
protected void flingToHeight(float vel, boolean expand, float target,
float collapseSpeedUpFactor, boolean expandBecauseOfFalsing) {
mHeadsUpTouchHelper.notifyFling(!expand);
- setClosingWithAlphaFadeout(!expand
- && mNotificationStackScroller.getFirstChildIntrinsicHeight() <= mMaxFadeoutHeight
- && getFadeoutAlpha() == 1.0f);
+ setClosingWithAlphaFadeout(!expand && getFadeoutAlpha() == 1.0f);
super.flingToHeight(vel, expand, target, collapseSpeedUpFactor, expandBecauseOfFalsing);
}
@@ -734,6 +733,11 @@
}
@Override
+ protected float getOpeningHeight() {
+ return mNotificationStackScroller.getMinExpansionHeight();
+ }
+
+ @Override
public boolean onTouchEvent(MotionEvent event) {
if (mBlockTouches || (mQs != null && mQs.isCustomizing())) {
return false;
@@ -1426,7 +1430,7 @@
if (mKeyguardShowing) {
// On Keyguard, interpolate the QS expansion linearly to the panel expansion
- t = expandedHeight / getMaxPanelHeight();
+ t = expandedHeight / (getMaxPanelHeight());
} else {
// In Shade, interpolate linearly such that QS is closed whenever panel height is
@@ -2276,6 +2280,14 @@
protected void updateExpandedHeight(float expandedHeight) {
mNotificationStackScroller.setExpandedHeight(expandedHeight);
updateKeyguardBottomAreaAlpha();
+ setOpening(expandedHeight <= getOpeningHeight());
+ }
+
+ private void setOpening(boolean opening) {
+ if (opening != mOpening) {
+ mOpening = opening;
+ mStatusBar.recomputeDisableFlags(false);
+ }
}
public void setPanelScrimMinFraction(float minFraction) {
@@ -2327,7 +2339,18 @@
@Override
public void setAlpha(float alpha) {
super.setAlpha(alpha);
- mNotificationStackScroller.setParentFadingOut(alpha != 1.0f);
+ updateFullyVisibleState();
+ }
+
+ @Override
+ public void setVisibility(int visibility) {
+ super.setVisibility(visibility);
+ updateFullyVisibleState();
+ }
+
+ private void updateFullyVisibleState() {
+ mNotificationStackScroller.setParentNotFullyVisible(getAlpha() != 1.0f
+ || getVisibility() != VISIBLE);
}
/**
@@ -2369,6 +2392,15 @@
mGroupManager = groupManager;
}
+ public boolean shouldHideNotificationIcons() {
+ return !mOpening && !isFullyCollapsed();
+ }
+
+ public boolean shouldAnimateIconHiding() {
+ // TODO: handle this correctly, not completely working yet
+ return mNotificationStackScroller.getTranslationX() != 0;
+ }
+
private final FragmentListener mFragmentListener = new FragmentListener() {
@Override
public void onFragmentViewCreated(String tag, Fragment fragment) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index f2c57e5..87a3848 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -118,7 +118,7 @@
boolean fullyOpened = false;
if (SPEW) LOG("panelExpansionChanged: start state=%d", mState);
PanelView pv = mPanel;
- pv.setVisibility(expanded ? View.VISIBLE : View.INVISIBLE);
+ pv.setVisibility(expanded ? VISIBLE : INVISIBLE);
// adjust any other panels that may be partially visible
if (expanded) {
if (mState == STATE_CLOSED) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 3de03b5..570d5d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -23,6 +23,7 @@
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
import android.view.InputDevice;
@@ -50,6 +51,10 @@
public abstract class PanelView extends FrameLayout {
public static final boolean DEBUG = PanelBar.DEBUG;
public static final String TAG = PanelView.class.getSimpleName();
+ private static final int INITIAL_OPENING_PEEK_DURATION = 200;
+ private static final int PEEK_ANIMATION_DURATION = 360;
+ private long mDownTime;
+ private float mMinExpandHeight;
private final void logf(String fmt, Object... args) {
Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
@@ -88,6 +93,7 @@
private ObjectAnimator mPeekAnimator;
private VelocityTrackerInterface mVelocityTracker;
private FlingAnimationUtils mFlingAnimationUtils;
+ private FlingAnimationUtils mFlingAnimationUtilsClosing;
private FalsingManager mFalsingManager;
/**
@@ -106,9 +112,6 @@
private Interpolator mBounceInterpolator;
protected KeyguardBottomAreaView mKeyguardBottomArea;
- private boolean mPeekPending;
- private boolean mCollapseAfterPeek;
-
/**
* Speed-up factor to be used when {@link #mFlingCollapseRunnable} runs the next time.
*/
@@ -118,13 +121,6 @@
private boolean mGestureWaitForTouchSlop;
private boolean mIgnoreXTouchSlop;
private boolean mExpandLatencyTracking;
- private Runnable mPeekRunnable = new Runnable() {
- @Override
- public void run() {
- mPeekPending = false;
- runPeekAnimation();
- }
- };
protected void onExpandingFinished() {
mBar.onExpandingFinished();
@@ -148,21 +144,17 @@
}
}
- private void schedulePeek() {
- mPeekPending = true;
- long timeout = ViewConfiguration.getTapTimeout();
- postOnAnimationDelayed(mPeekRunnable, timeout);
- notifyBarPanelExpansionChanged();
- }
-
- private void runPeekAnimation() {
- mPeekHeight = getPeekHeight();
+ private void runPeekAnimation(long duration, float peekHeight, boolean collapseWhenFinished) {
+ mPeekHeight = peekHeight;
if (DEBUG) logf("peek to height=%.1f", mPeekHeight);
if (mHeightAnimator != null) {
return;
}
+ if (mPeekAnimator != null) {
+ mPeekAnimator.cancel();
+ }
mPeekAnimator = ObjectAnimator.ofFloat(this, "expandedHeight", mPeekHeight)
- .setDuration(250);
+ .setDuration(duration);
mPeekAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
mPeekAnimator.addListener(new AnimatorListenerAdapter() {
private boolean mCancelled;
@@ -175,10 +167,10 @@
@Override
public void onAnimationEnd(Animator animation) {
mPeekAnimator = null;
- if (mCollapseAfterPeek && !mCancelled) {
+ if (!mCancelled && collapseWhenFinished) {
postOnAnimation(mPostCollapseRunnable);
}
- mCollapseAfterPeek = false;
+
}
});
notifyExpandingStarted();
@@ -189,6 +181,7 @@
public PanelView(Context context, AttributeSet attrs) {
super(context, attrs);
mFlingAnimationUtils = new FlingAnimationUtils(context, 0.6f);
+ mFlingAnimationUtilsClosing = new FlingAnimationUtils(context, 0.4f);
mBounceInterpolator = new BounceInterpolator();
mFalsingManager = FalsingManager.getInstance(context);
}
@@ -267,11 +260,13 @@
case MotionEvent.ACTION_DOWN:
startExpandMotion(x, y, false /* startTracking */, mExpandedHeight);
mJustPeeked = false;
+ mMinExpandHeight = 0.0f;
mPanelClosedOnDown = isFullyCollapsed();
mHasLayoutedSinceDown = false;
mUpdateFlingOnLayout = false;
mMotionAborted = false;
mPeekTouching = mPanelClosedOnDown;
+ mDownTime = SystemClock.uptimeMillis();
mTouchAboveFalsingThreshold = false;
mCollapsedAndHeadsUpOnDown = isFullyCollapsed()
&& mHeadsUpManager.hasPinnedHeadsUp();
@@ -279,16 +274,16 @@
initVelocityTracker();
}
trackMovement(event);
- if (!mGestureWaitForTouchSlop || (mHeightAnimator != null && !mHintAnimationRunning) ||
- mPeekPending || mPeekAnimator != null) {
+ if (!mGestureWaitForTouchSlop || (mHeightAnimator != null && !mHintAnimationRunning)
+ || mPeekAnimator != null) {
cancelHeightAnimator();
cancelPeek();
mTouchSlopExceeded = (mHeightAnimator != null && !mHintAnimationRunning)
- || mPeekPending || mPeekAnimator != null;
+ || mPeekAnimator != null;
onTrackingStarted();
}
if (isFullyCollapsed() && !mHeadsUpManager.hasPinnedHeadsUp()) {
- schedulePeek();
+ startOpening();
}
break;
@@ -317,7 +312,7 @@
// y-component of the gesture, as we have no conflicting horizontal gesture.
if (Math.abs(h) > mTouchSlop
&& (Math.abs(h) > Math.abs(x - mInitialTouchX)
- || mIgnoreXTouchSlop)) {
+ || mIgnoreXTouchSlop)) {
mTouchSlopExceeded = true;
if (mGestureWaitForTouchSlop && !mTracking && !mCollapsedAndHeadsUpOnDown) {
if (!mJustPeeked && mInitialOffsetOnTouch != 0f) {
@@ -325,23 +320,30 @@
h = 0;
}
cancelHeightAnimator();
- removeCallbacks(mPeekRunnable);
- mPeekPending = false;
onTrackingStarted();
}
}
- final float newHeight = Math.max(0, h + mInitialOffsetOnTouch);
+ float newHeight = Math.max(0, h + mInitialOffsetOnTouch);
if (newHeight > mPeekHeight) {
if (mPeekAnimator != null) {
mPeekAnimator.cancel();
}
mJustPeeked = false;
+ } else if (mPeekAnimator == null && mJustPeeked) {
+ // The initial peek has finished, but we haven't dragged as far yet, lets
+ // speed it up by starting at the peek height.
+ mInitialOffsetOnTouch = mExpandedHeight;
+ mInitialTouchY = y;
+ mMinExpandHeight = mExpandedHeight;
+ mJustPeeked = false;
}
+ newHeight = Math.max(newHeight, mMinExpandHeight);
if (-h >= getFalsingThreshold()) {
mTouchAboveFalsingThreshold = true;
mUpwardsWhenTresholdReached = isDirectionUpwards(x, y);
}
- if (!mJustPeeked && (!mGestureWaitForTouchSlop || mTracking) && !isTrackingBlocked()) {
+ if (!mJustPeeked && (!mGestureWaitForTouchSlop || mTracking) &&
+ !isTrackingBlocked()) {
setExpandedHeightInternal(newHeight);
}
@@ -357,6 +359,14 @@
return !mGestureWaitForTouchSlop || mTracking;
}
+ private void startOpening() {;
+ runPeekAnimation(INITIAL_OPENING_PEEK_DURATION, getOpeningHeight(),
+ false /* collapseWhenFinished */);
+ notifyBarPanelExpansionChanged();
+ }
+
+ protected abstract float getOpeningHeight();
+
/**
* @return whether the swiping direction is upwards and above a 45 degree angle compared to the
* horizontal direction
@@ -418,6 +428,15 @@
if (mUpdateFlingOnLayout) {
mUpdateFlingVelocity = vel;
}
+ } else if (mPanelClosedOnDown && !mHeadsUpManager.hasPinnedHeadsUp() && !mTracking) {
+ long timePassed = SystemClock.uptimeMillis() - mDownTime;
+ if (timePassed < ViewConfiguration.getLongPressTimeout()) {
+ // Lets show the user that he can actually expand the panel
+ runPeekAnimation(PEEK_ANIMATION_DURATION, getPeekHeight(), true /* collapseWhenFinished */);
+ } else {
+ // We need to collapse the panel since we peeked to the small height.
+ postOnAnimation(mPostCollapseRunnable);
+ }
} else {
boolean expands = onEmptySpaceClick(mInitialTouchX);
onTrackingStopped(expands);
@@ -448,7 +467,6 @@
protected void onTrackingStarted() {
endClosing();
mTracking = true;
- mCollapseAfterPeek = false;
mBar.onTrackingStarted();
notifyExpandingStarted();
notifyBarPanelExpansionChanged();
@@ -482,7 +500,10 @@
case MotionEvent.ACTION_DOWN:
mStatusBar.userActivity();
mAnimatingOnDown = mHeightAnimator != null;
- if (mAnimatingOnDown && mClosing && !mHintAnimationRunning || mPeekPending || mPeekAnimator != null) {
+ mMinExpandHeight = 0.0f;
+ mDownTime = SystemClock.uptimeMillis();
+ if (mAnimatingOnDown && mClosing && !mHintAnimationRunning
+ || mPeekAnimator != null) {
cancelHeightAnimator();
cancelPeek();
mTouchSlopExceeded = true;
@@ -639,7 +660,7 @@
protected void fling(float vel, boolean expand, float collapseSpeedUpFactor,
boolean expandBecauseOfFalsing) {
cancelPeek();
- float target = expand ? getMaxPanelHeight() : 0.0f;
+ float target = expand ? getMaxPanelHeight() : 0;
if (!expand) {
mClosing = true;
}
@@ -672,8 +693,7 @@
animator.setDuration(350);
}
} else {
- mFlingAnimationUtils.applyDismissing(animator, mExpandedHeight, target, vel,
- getHeight());
+ mFlingAnimationUtilsClosing.apply(animator, mExpandedHeight, target, vel, getHeight());
// Make it shorter if we run a canned animation
if (vel == 0) {
@@ -742,7 +762,6 @@
&& mHeightAnimator == null
&& !isFullyCollapsed()
&& currentMaxPanelHeight != mExpandedHeight
- && !mPeekPending
&& mPeekAnimator == null
&& !mPeekTouching) {
setExpandedHeight(currentMaxPanelHeight);
@@ -769,10 +788,8 @@
}
}
- mExpandedHeight = Math.max(0, mExpandedHeight);
- mExpandedFraction = Math.min(1f, fhWithoutOverExpansion == 0
- ? 0
- : mExpandedHeight / fhWithoutOverExpansion);
+ mExpandedFraction = Math.min(1f,
+ fhWithoutOverExpansion == 0 ? 0 : mExpandedHeight / fhWithoutOverExpansion);
onHeightUpdated(mExpandedHeight);
notifyBarPanelExpansionChanged();
}
@@ -816,7 +833,7 @@
}
public boolean isFullyCollapsed() {
- return mExpandedHeight <= 0;
+ return mExpandedFraction <= 0.0f;
}
public boolean isCollapsing() {
@@ -833,16 +850,7 @@
public void collapse(boolean delayed, float speedUpFactor) {
if (DEBUG) logf("collapse: " + this);
- if (mPeekPending || mPeekAnimator != null) {
- mCollapseAfterPeek = true;
- if (mPeekPending) {
-
- // We know that the whole gesture is just a peek triggered by a simple click, so
- // better start it now.
- removeCallbacks(mPeekRunnable);
- mPeekRunnable.run();
- }
- } else if (!isFullyCollapsed() && !mTracking && !mClosing) {
+ if (!isFullyCollapsed() && !mTracking && !mClosing) {
cancelHeightAnimator();
notifyExpandingStarted();
@@ -866,13 +874,11 @@
};
public void cancelPeek() {
- boolean cancelled = mPeekPending;
+ boolean cancelled = false;
if (mPeekAnimator != null) {
cancelled = true;
mPeekAnimator.cancel();
}
- removeCallbacks(mPeekRunnable);
- mPeekPending = false;
if (cancelled) {
// When peeking, we already tell mBar that we expanded ourselves. Make sure that we also
@@ -1048,7 +1054,7 @@
}
protected void notifyBarPanelExpansionChanged() {
- mBar.panelExpansionChanged(mExpandedFraction, mExpandedFraction > 0f || mPeekPending
+ mBar.panelExpansionChanged(mExpandedFraction, mExpandedFraction > 0f
|| mPeekAnimator != null || mInstantExpanding || isPanelVisibleBecauseOfHeadsUp()
|| mTracking || mHeightAnimator != null);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index fb51f51..604e8e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1054,7 +1054,7 @@
private void inflateShelf() {
mNotificationShelf =
(NotificationShelf) LayoutInflater.from(mContext).inflate(
- R.layout.status_bar_notification_icon_container, mStackScroller, false);
+ R.layout.status_bar_notification_shelf, mStackScroller, false);
mNotificationShelf.setOnActivatedListener(this);
mNotificationShelf.setOnClickListener(mShelfClickListener);
mStackScroller.setShelf(mNotificationShelf);
@@ -2005,10 +2005,12 @@
}
currentIndex++;
}
+ boolean noAmbient = false;
if (shelfIndex == -1) {
shelfIndex = currentIndex;
+ noAmbient = true;
}
- mStackScroller.updateShelfIndex(shelfIndex);
+ mStackScroller.updateShelfIndex(shelfIndex, noAmbient);
}
public static boolean isTopLevelChild(Entry entry) {
@@ -2380,8 +2382,7 @@
}
protected int adjustDisableFlags(int state) {
- if (!mLaunchTransitionFadingAway && !mKeyguardFadingAway
- && (mExpandedVisible || mBouncerShowing || mWaitingForKeyguardExit)) {
+ if (!mLaunchTransitionFadingAway && !mKeyguardFadingAway && shouldHideNotificationIcons()) {
state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
state |= StatusBarManager.DISABLE_SYSTEM_INFO;
}
@@ -2396,6 +2397,10 @@
return state;
}
+ private boolean shouldHideNotificationIcons() {
+ return mExpandedVisible && mNotificationPanel.shouldHideNotificationIcons();
+ }
+
/**
* State is one or more of the DISABLE constants from StatusBarManager.
*/
@@ -2502,7 +2507,7 @@
*
* This needs to be called if state used by {@link #adjustDisableFlags} changes.
*/
- private void recomputeDisableFlags(boolean animate) {
+ public void recomputeDisableFlags(boolean animate) {
disable(mDisabledUnmodified1, mDisabledUnmodified2, animate);
}
@@ -2948,7 +2953,7 @@
runPostCollapseRunnables();
setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
showBouncer();
- recomputeDisableFlags(true /* animate */);
+ recomputeDisableFlags(shouldAnimatIconHiding() /* animate */);
// Trimming will happen later if Keyguard is showing - doing it here might cause a jank in
// the bouncer appear animation.
@@ -2957,6 +2962,10 @@
}
}
+ private boolean shouldAnimatIconHiding() {
+ return mNotificationPanel.shouldAnimateIconHiding();
+ }
+
public boolean interceptTouchEvent(MotionEvent event) {
if (DEBUG_GESTURES) {
if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
@@ -4166,7 +4175,7 @@
mScrimController.forceHideScrims(true /* hide */);
updateMediaMetaData(false, true);
mNotificationPanel.setAlpha(1);
- mStackScroller.setParentFadingOut(true);
+ mStackScroller.setParentNotFullyVisible(true);
mNotificationPanel.animate()
.alpha(0)
.setStartDelay(FADE_KEYGUARD_START_DELAY)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 6217433..f6dd88d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -235,7 +235,7 @@
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getActionMasked() == MotionEvent.ACTION_DOWN
- && mNotificationPanel.getExpandedHeight() == 0f) {
+ && mNotificationPanel.isFullyCollapsed()) {
mNotificationPanel.startExpandLatencyTracking();
}
mFalsingManager.onTouchEvent(ev, getWidth(), getHeight());