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 72c10eb7eaee1..3a1752dda756f 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; @@ -454,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; @@ -645,6 +650,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 +1032,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/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(); } } 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 0636b867cba6f..80eec7ee6fd13 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,20 @@ public class NotificationStackScrollLayout extends ViewGroup private boolean mPulsing; 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 +422,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(); } @@ -930,6 +950,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; } @@ -1558,6 +1602,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. @@ -1602,14 +1664,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; } @@ -2580,6 +2634,7 @@ public class NotificationStackScrollLayout extends ViewGroup AnimationEvent ev = new AnimationEvent(null, AnimationEvent.ANIMATION_TYPE_DARK); ev.darkAnimationOriginIndex = mDarkAnimationOriginIndex; mAnimationEvents.add(ev); + startBackgroundFadeIn(); } mDarkNeedsAnimation = false; } @@ -2885,8 +2940,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; @@ -2895,6 +2949,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; @@ -3080,6 +3139,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) { @@ -3088,10 +3150,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; @@ -3375,13 +3462,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