From 1b2a05eb00746756c4d37ad76d597d909019e56f Mon Sep 17 00:00:00 2001 From: Selim Cinek Date: Thu, 28 Apr 2016 14:20:39 -0700 Subject: [PATCH 1/3] Fixed the animation when flinging over the bottom stack The new approach is still not perfect but has way less artifacts. Change-Id: I096d3823c5ede720bdf05558d68529e903dce5b5 Fixes: 27744811 --- .../com/android/systemui/ExpandHelper.java | 3 +- .../statusbar/ExpandableNotificationRow.java | 13 +++- .../stack/NotificationStackScrollLayout.java | 66 +++++++++++++++---- 3 files changed, 68 insertions(+), 14 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java index cecbfcb236bab..b6d8095d6c839 100644 --- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java +++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java @@ -44,6 +44,7 @@ public class ExpandHelper implements Gefingerpoken { void setUserExpandedChild(View v, boolean userExpanded); void setUserLockedChild(View v, boolean userLocked); void expansionStateChanged(boolean isExpanding); + int getMaxExpandHeight(ExpandableView view); } private static final String TAG = "ExpandHelper"; @@ -144,7 +145,7 @@ public class ExpandHelper implements Gefingerpoken { return mView.getActualHeight(); } public int getNaturalHeight() { - return mView.getMaxContentHeight(); + return mCallback.getMaxExpandHeight(mView); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java index 1b31edb2ac16b..b25adc3f2cfce 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java @@ -156,6 +156,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { } } }; + private boolean mForceUnlocked; private boolean mDismissed; private boolean mKeepInParent; private boolean mRemoved; @@ -645,6 +646,16 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { onChildrenCountChanged(); } + public void setForceUnlocked(boolean forceUnlocked) { + mForceUnlocked = forceUnlocked; + if (mIsSummaryWithChildren) { + List notificationChildren = getNotificationChildren(); + for (ExpandableNotificationRow child : notificationChildren) { + child.setForceUnlocked(forceUnlocked); + } + } + } + public void setDismissed(boolean dismissed) { mDismissed = dismissed; } @@ -1017,7 +1028,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { } public boolean isUserLocked() { - return mUserLocked; + return mUserLocked && !mForceUnlocked; } public void setUserLocked(boolean userLocked) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index 4c8f27d5fa8c2..e62a524b31f7b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -330,6 +330,7 @@ public class NotificationStackScrollLayout extends ViewGroup private boolean mPulsing; private boolean mDrawBackgroundAsSrc; private boolean mFadedOut; + private boolean mGroupExpandedForMeasure; public NotificationStackScrollLayout(Context context) { this(context, null); @@ -929,6 +930,30 @@ public class NotificationStackScrollLayout extends ViewGroup } } + @Override + public int getMaxExpandHeight(ExpandableView view) { + int maxContentHeight = view.getMaxContentHeight(); + if (view.isSummaryWithChildren()) { + // Faking a measure with the group expanded to simulate how the group would look if + // it was. Doing a calculation here would be highly non-trivial because of the + // algorithm + mGroupExpandedForMeasure = true; + ExpandableNotificationRow row = (ExpandableNotificationRow) view; + mGroupManager.toggleGroupExpansion(row.getStatusBarNotification()); + row.setForceUnlocked(true); + mAmbientState.setLayoutHeight(mMaxLayoutHeight); + mStackScrollAlgorithm.getStackScrollState(mAmbientState, mCurrentStackScrollState); + mAmbientState.setLayoutHeight(getLayoutHeight()); + mGroupManager.toggleGroupExpansion( + row.getStatusBarNotification()); + mGroupExpandedForMeasure = false; + row.setForceUnlocked(false); + int height = mCurrentStackScrollState.getViewStateForView(view).height; + return Math.min(height, maxContentHeight); + } + return maxContentHeight; + } + public void setScrollingEnabled(boolean enable) { mScrollingEnabled = enable; } @@ -1547,6 +1572,24 @@ public class NotificationStackScrollLayout extends ViewGroup return null; } + /** + * @return the child before the given view which has visibility unequal to GONE + */ + public ExpandableView getViewBeforeView(ExpandableView view) { + ExpandableView previousView = null; + int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + View child = getChildAt(i); + if (child == view) { + return previousView; + } + if (child.getVisibility() != View.GONE) { + previousView = (ExpandableView) child; + } + } + return null; + } + /** * @return The first child which has visibility unequal to GONE which is currently below the * given translationY or equal to it. @@ -1591,14 +1634,6 @@ public class NotificationStackScrollLayout extends ViewGroup return count; } - private int getMaxExpandHeight(View view) { - if (view instanceof ExpandableNotificationRow) { - ExpandableNotificationRow row = (ExpandableNotificationRow) view; - return row.getIntrinsicHeight(); - } - return view.getHeight(); - } - public int getContentHeight() { return mContentHeight; } @@ -2867,8 +2902,7 @@ public class NotificationStackScrollLayout extends ViewGroup if (row.isChildInGroup()) { endPosition += row.getNotificationParent().getTranslationY(); } - int stackEnd = mMaxLayoutHeight - mBottomStackPeekSize - - mBottomStackSlowDownHeight + (int) mStackTranslation; + int stackEnd = getStackEndPosition(); if (endPosition > stackEnd) { mOwnScrollY += endPosition - stackEnd; mDisallowScrollingInThisMotion = true; @@ -2877,6 +2911,11 @@ public class NotificationStackScrollLayout extends ViewGroup } } + private int getStackEndPosition() { + return mMaxLayoutHeight - mBottomStackPeekSize - mBottomStackSlowDownHeight + + mPaddingBetweenElements + (int) mStackTranslation; + } + public void setOnHeightChangedListener( ExpandableView.OnHeightChangedListener mOnHeightChangedListener) { this.mOnHeightChangedListener = mOnHeightChangedListener; @@ -3357,13 +3396,16 @@ public class NotificationStackScrollLayout extends ViewGroup @Override public void onGroupExpansionChanged(ExpandableNotificationRow changedRow, boolean expanded) { - boolean animated = mAnimationsEnabled && (mIsExpanded || changedRow.isPinned()); + boolean animated = !mGroupExpandedForMeasure && mAnimationsEnabled + && (mIsExpanded || changedRow.isPinned()); if (animated) { mExpandedGroupView = changedRow; mNeedsAnimation = true; } changedRow.setChildrenExpanded(expanded, animated); - onHeightChanged(changedRow, false /* needsAnimation */); + if (!mGroupExpandedForMeasure) { + onHeightChanged(changedRow, false /* needsAnimation */); + } } @Override From 972123d1f1b5dd276c5e81357e4598b96d6f6a5a Mon Sep 17 00:00:00 2001 From: Selim Cinek Date: Tue, 3 May 2016 14:25:58 -0700 Subject: [PATCH 2/3] Fixed the fade in animation when coming from dark Previously the fade-in wasn't happening which is now working. Change-Id: I34496c735043058009e9cc9bbf169ffa742a78c4 Fixes: 27534592 --- .../stack/NotificationStackScrollLayout.java | 56 +++++++++++++++++-- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index e62a524b31f7b..c1dc66cef11ea 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -36,8 +36,10 @@ import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.os.Handler; import android.util.AttributeSet; +import android.util.FloatProperty; import android.util.Log; import android.util.Pair; +import android.util.Property; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; @@ -331,6 +333,19 @@ public class NotificationStackScrollLayout extends ViewGroup private boolean mDrawBackgroundAsSrc; private boolean mFadedOut; private boolean mGroupExpandedForMeasure; + private float mBackgroundFadeAmount = 1.0f; + private static final Property BACKGROUND_FADE = + new FloatProperty("backgroundFade") { + @Override + public void setValue(NotificationStackScrollLayout object, float value) { + object.setBackgroundFadeAmount(value); + } + + @Override + public Float get(NotificationStackScrollLayout object) { + return object.getBackgroundFadeAmount(); + } + }; public NotificationStackScrollLayout(Context context) { this(context, null); @@ -406,14 +421,18 @@ public class NotificationStackScrollLayout extends ViewGroup private void updateBackgroundDimming() { float alpha = BACKGROUND_ALPHA_DIMMED + (1 - BACKGROUND_ALPHA_DIMMED) * (1.0f - mDimAmount); + alpha *= mBackgroundFadeAmount; // We need to manually blend in the background color int scrimColor = mScrimController.getScrimBehindColor(); // SRC_OVER blending Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc float alphaInv = 1 - alpha; int color = Color.argb((int) (alpha * 255 + alphaInv * Color.alpha(scrimColor)), - (int) (Color.red(mBgColor) + alphaInv * Color.red(scrimColor)), - (int) (Color.green(mBgColor) + alphaInv * Color.green(scrimColor)), - (int) (Color.blue(mBgColor) + alphaInv * Color.blue(scrimColor))); + (int) (mBackgroundFadeAmount * Color.red(mBgColor) + + alphaInv * Color.red(scrimColor)), + (int) (mBackgroundFadeAmount * Color.green(mBgColor) + + alphaInv * Color.green(scrimColor)), + (int) (mBackgroundFadeAmount * Color.blue(mBgColor) + + alphaInv * Color.blue(scrimColor))); mBackgroundPaint.setColor(color); invalidate(); } @@ -2602,6 +2621,7 @@ public class NotificationStackScrollLayout extends ViewGroup AnimationEvent ev = new AnimationEvent(null, AnimationEvent.ANIMATION_TYPE_DARK); ev.darkAnimationOriginIndex = mDarkAnimationOriginIndex; mAnimationEvents.add(ev); + startBackgroundFadeIn(); } mDarkNeedsAnimation = false; } @@ -3101,6 +3121,9 @@ public class NotificationStackScrollLayout extends ViewGroup mDarkNeedsAnimation = true; mDarkAnimationOriginIndex = findDarkAnimationOriginIndex(touchWakeUpScreenLocation); mNeedsAnimation = true; + setBackgroundFadeAmount(0.0f); + } else if (!dark) { + setBackgroundFadeAmount(1.0f); } requestChildrenUpdate(); if (dark) { @@ -3109,10 +3132,35 @@ public class NotificationStackScrollLayout extends ViewGroup } else { updateBackground(); setWillNotDraw(false); - // TODO: fade in background } } + private void setBackgroundFadeAmount(float fadeAmount) { + mBackgroundFadeAmount = fadeAmount; + updateBackgroundDimming(); + } + + public float getBackgroundFadeAmount() { + return mBackgroundFadeAmount; + } + + private void startBackgroundFadeIn() { + ObjectAnimator fadeAnimator = ObjectAnimator.ofFloat(this, BACKGROUND_FADE, 0f, 1f); + int maxLength; + if (mDarkAnimationOriginIndex == AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_ABOVE + || mDarkAnimationOriginIndex == AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_BELOW) { + maxLength = getNotGoneChildCount() - 1; + } else { + maxLength = Math.max(mDarkAnimationOriginIndex, + getNotGoneChildCount() - mDarkAnimationOriginIndex - 1); + } + long delay = maxLength * StackStateAnimator.ANIMATION_DELAY_PER_ELEMENT_DARK; + fadeAnimator.setStartDelay(delay); + fadeAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); + fadeAnimator.setInterpolator(Interpolators.ALPHA_IN); + fadeAnimator.start(); + } + private int findDarkAnimationOriginIndex(@Nullable PointF screenLocation) { if (screenLocation == null || screenLocation.y < mTopPadding + mTopPaddingOverflow) { return AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_ABOVE; From def35a86530200958384191d43d321dbcda16e2a Mon Sep 17 00:00:00 2001 From: Selim Cinek Date: Tue, 3 May 2016 15:52:51 -0700 Subject: [PATCH 3/3] Fixed a bug where the content height was wrong when dragging down from a HUN the content height was wrong. Change-Id: Ic30e4de67625ed88942c71e68e6009b832d064ed Fixes: 28563238 --- .../android/systemui/statusbar/ExpandableNotificationRow.java | 4 ++++ .../android/systemui/statusbar/phone/HeadsUpTouchHelper.java | 4 +++- .../src/com/android/systemui/statusbar/phone/PanelView.java | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java index b25adc3f2cfce..1a34dd79d63ae 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java @@ -455,7 +455,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { * @param pinned whether it is pinned */ public void setPinned(boolean pinned) { + int intrinsicHeight = getIntrinsicHeight(); mIsPinned = pinned; + if (intrinsicHeight != getIntrinsicHeight()) { + notifyHeightChanged(false); + } if (pinned) { setIconAnimationRunning(true); mExpandedWhenPinned = false; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java index 33315c58fb4ae..bd59fb03d59ae 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java @@ -103,10 +103,12 @@ public class HeadsUpTouchHelper implements Gefingerpoken { mInitialTouchX = x; mInitialTouchY = y; int expandedHeight = mPickedChild.getActualHeight(); - mHeadsUpManager.unpinAll(); mPanel.setPanelScrimMinFraction((float) expandedHeight / mPanel.getMaxPanelHeight()); mPanel.startExpandMotion(x, y, true /* startTracking */, expandedHeight); + // This call needs to be after the expansion start otherwise we will get a + // flicker of one frame as it's not expanded yet. + mHeadsUpManager.unpinAll(); mPanel.clearNotificationEffects(); return true; } 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 7c70e22c5302f..e4aa10361e874 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -362,6 +362,7 @@ public abstract class PanelView extends FrameLayout { mInitialTouchX = newX; if (startTracking) { mTouchSlopExceeded = true; + setExpandedHeight(mInitialOffsetOnTouch); onTrackingStarted(); } }