diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index de88e6650245f..ada24f37e6d5e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -16,8 +16,6 @@ package com.android.systemui.statusbar; -import static com.android.systemui.statusbar.phone.NotificationIconContainer.IconState; - import android.content.Context; import android.content.res.Configuration; import android.util.AttributeSet; @@ -157,6 +155,7 @@ public class NotificationShelf extends ActivatableNotificationView { mShelfState.shadowAlpha = 1.0f; mShelfState.isBottomClipped = false; mShelfState.hideSensitive = false; + mShelfState.xTranslation = getTranslationX(); if (mNotGoneIndex != -1) { mShelfState.notGoneIndex = Math.min(mShelfState.notGoneIndex, mNotGoneIndex); } @@ -173,7 +172,7 @@ public class NotificationShelf extends ActivatableNotificationView { * the icons from the notification area into the shelf. */ public void updateAppearance() { - WeakHashMap iconStates = + WeakHashMap iconStates = mShelfIcons.resetViewStates(); float numIconsInShelf = 0.0f; int shelfIndex = mAmbientState.getShelfIndex(); @@ -196,7 +195,7 @@ public class NotificationShelf extends ActivatableNotificationView { } ExpandableNotificationRow row = (ExpandableNotificationRow) child; StatusBarIconView icon = row.getEntry().expandedIcon; - IconState iconState = iconStates.get(icon); + NotificationIconContainer.IconState iconState = iconStates.get(icon); float notificationClipEnd; float shelfStart = getTranslationY(); boolean aboveShelf = row.getTranslationZ() > mAmbientState.getBaseZHeight(); @@ -255,8 +254,9 @@ public class NotificationShelf extends ActivatableNotificationView { } } - private void updateIconAppearance(ExpandableNotificationRow row, IconState iconState, - StatusBarIconView icon, float expandAmount) { + private void updateIconAppearance(ExpandableNotificationRow row, + NotificationIconContainer.IconState iconState, StatusBarIconView icon, + float expandAmount) { // Let calculate how much the view is in the shelf float viewStart = row.getTranslationY(); int transformHeight = row.getActualHeight() + mPaddingBetweenElements; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java index 543f899283d4b..d635bb06d318c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java @@ -19,7 +19,6 @@ package com.android.systemui.statusbar; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; -import android.animation.ValueAnimator; import android.app.Notification; import android.content.Context; import android.content.pm.ApplicationInfo; @@ -68,7 +67,7 @@ public class StatusBarIconView extends AnimatedImageView { return object.getIconAppearAmount(); } }; - private static final Property DOT_APPEAR_AMOUNG + private static final Property DOT_APPEAR_AMOUNT = new FloatProperty("dot_appear_amount") { @Override @@ -440,54 +439,75 @@ public class StatusBarIconView extends AnimatedImageView { mDotPaint.setColor(iconTint); } - public void setVisibleState(int visibleState) { + public void setVisibleState(int state) { + setVisibleState(state, true /* animate */, null /* endRunnable */); + } + + public void setVisibleState(int state, boolean animate) { + setVisibleState(state, animate, null); + } + + @Override + public boolean hasOverlappingRendering() { + return false; + } + + public void setVisibleState(int visibleState, boolean animate, Runnable endRunnable) { if (visibleState != mVisibleState) { mVisibleState = visibleState; - if (mIconAppearAnimator != null) { - mIconAppearAnimator.cancel(); - } - float targetAmount = 0.0f; - Interpolator interpolator = Interpolators.FAST_OUT_LINEAR_IN; - if (visibleState == STATE_ICON) { - targetAmount = 1.0f; - interpolator = Interpolators.LINEAR_OUT_SLOW_IN; - } - mIconAppearAnimator = ObjectAnimator.ofFloat(this, ICON_APPEAR_AMOUNT, - targetAmount); - mIconAppearAnimator.setInterpolator(interpolator); - mIconAppearAnimator.setDuration(100); - mIconAppearAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mIconAppearAnimator = null; + if (animate) { + if (mIconAppearAnimator != null) { + mIconAppearAnimator.cancel(); } - }); - mIconAppearAnimator.start(); + float targetAmount = 0.0f; + Interpolator interpolator = Interpolators.FAST_OUT_LINEAR_IN; + if (visibleState == STATE_ICON) { + targetAmount = 1.0f; + interpolator = Interpolators.LINEAR_OUT_SLOW_IN; + } + mIconAppearAnimator = ObjectAnimator.ofFloat(this, ICON_APPEAR_AMOUNT, + targetAmount); + mIconAppearAnimator.setInterpolator(interpolator); + mIconAppearAnimator.setDuration(100); + mIconAppearAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mIconAppearAnimator = null; + if (endRunnable != null) { + endRunnable.run(); + } + } + }); + mIconAppearAnimator.start(); - if (mDotAnimator != null) { - mDotAnimator.cancel(); - } - targetAmount = visibleState == STATE_ICON ? 2.0f : 0.0f; - interpolator = Interpolators.FAST_OUT_LINEAR_IN; - if (visibleState == STATE_DOT) { - targetAmount = 1.0f; - interpolator = Interpolators.LINEAR_OUT_SLOW_IN; - } - mDotAnimator = ObjectAnimator.ofFloat(this, DOT_APPEAR_AMOUNG, - targetAmount); - mDotAnimator.setInterpolator(interpolator); - mDotAnimator.setDuration(100); - mDotAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mDotAnimator = null; + if (mDotAnimator != null) { + mDotAnimator.cancel(); } - }); - mDotAnimator.start(); + targetAmount = visibleState == STATE_ICON ? 2.0f : 0.0f; + interpolator = Interpolators.FAST_OUT_LINEAR_IN; + if (visibleState == STATE_DOT) { + targetAmount = 1.0f; + interpolator = Interpolators.LINEAR_OUT_SLOW_IN; + } + mDotAnimator = ObjectAnimator.ofFloat(this, DOT_APPEAR_AMOUNT, + targetAmount); + mDotAnimator.setInterpolator(interpolator); + mDotAnimator.setDuration(100); + mDotAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mDotAnimator = null; + } + }); + mDotAnimator.start(); + } else { + setIconAppearAmount(visibleState == STATE_ICON ? 1.0f : 0.0f); + setDotAppearAmount(visibleState == STATE_DOT ? 1.0f : 0.0f); + } } } - public void setIconAppearAmount(Float iconAppearAmount) { + public void setIconAppearAmount(float iconAppearAmount) { mIconAppearAmount = iconAppearAmount; invalidate(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java index 7b67f31b7a4a5..0dbff19b6bcf4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java @@ -36,7 +36,7 @@ public class NotificationIconAreaController { private PhoneStatusBar mPhoneStatusBar; protected View mNotificationIconArea; private NotificationIconContainer mNotificationIcons; - private NotificationIconContainer mNotificationIconsScroller; + private NotificationIconContainer mShelfIcons; private final Rect mTintArea = new Rect(); private NotificationStackScrollLayout mNotificationScrollLayout; private Context mContext; @@ -65,7 +65,7 @@ public class NotificationIconAreaController { R.id.notificationIcons); NotificationShelf shelf = mPhoneStatusBar.getNotificationShelf(); - mNotificationIconsScroller = shelf.getShelfIcons(); + mShelfIcons = shelf.getShelfIcons(); shelf.setCollapsedIcons(mNotificationIcons); mNotificationScrollLayout = mPhoneStatusBar.getNotificationScrollLayout(); @@ -147,8 +147,7 @@ public class NotificationIconAreaController { public void updateNotificationIcons(NotificationData notificationData) { updateIconsForLayout(notificationData, entry -> entry.icon, mNotificationIcons); - updateIconsForLayout(notificationData, entry -> entry.expandedIcon, - mNotificationIconsScroller); + updateIconsForLayout(notificationData, entry -> entry.expandedIcon, mShelfIcons); applyNotificationIconsTint(); ArrayList activeNotifications @@ -207,11 +206,14 @@ public class NotificationIconAreaController { final LinearLayout.LayoutParams params = generateIconLayoutParams(); for (int i = 0; i < toShow.size(); i++) { View v = toShow.get(i); + // The view might still be transiently added if it was just removed and added again + hostLayout.removeTransientView(v); if (v.getParent() == null) { hostLayout.addView(v, i, params); } } + hostLayout.setChangingViewPositions(true); // Re-sort notification icons final int childCount = hostLayout.getChildCount(); for (int i = 0; i < childCount; i++) { @@ -223,6 +225,7 @@ public class NotificationIconAreaController { hostLayout.removeView(expected); hostLayout.addView(expected, i); } + hostLayout.setChangingViewPositions(false); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java index 0f41e31d9b366..28958908f81bc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java @@ -40,13 +40,23 @@ import java.util.WeakHashMap; public class NotificationIconContainer extends AlphaOptimizedFrameLayout { private static final String TAG = "NotificationIconContainer"; private static final boolean DEBUG = false; - private static final AnimationFilter DOT_ANIMATION_FILTER = new AnimationFilter().animateX(); private static final AnimationProperties DOT_ANIMATION_PROPERTIES = new AnimationProperties() { + private AnimationFilter mAnimationFilter = new AnimationFilter().animateX(); + @Override public AnimationFilter getAnimationFilter() { - return DOT_ANIMATION_FILTER; + return mAnimationFilter; } }.setDuration(200); + + private static final AnimationProperties ADD_ICON_PROPERTIES = new AnimationProperties() { + private AnimationFilter mAnimationFilter = new AnimationFilter().animateAlpha(); + + @Override + public AnimationFilter getAnimationFilter() { + return mAnimationFilter; + } + }.setDuration(200).setDelay(50); private boolean mShowAllIcons = true; private WeakHashMap mIconStates = new WeakHashMap<>(); @@ -55,6 +65,8 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { private int mActualLayoutWidth = -1; private float mActualPaddingEnd = -1; private float mActualPaddingStart = -1; + private boolean mChangingViewPositions; + private int mAnimationStartIndex = -1; public NotificationIconContainer(Context context, AttributeSet attrs) { super(context, attrs); @@ -109,18 +121,60 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { childState.applyToView(child); } } + mAnimationStartIndex = -1; } @Override public void onViewAdded(View child) { super.onViewAdded(child); - mIconStates.put(child, new IconState()); + if (!mChangingViewPositions) { + mIconStates.put(child, new IconState()); + } + int childIndex = indexOfChild(child); + if (childIndex < getChildCount() - 1 + && mIconStates.get(getChildAt(childIndex + 1)).iconAppearAmount > 0.0f) { + if (mAnimationStartIndex < 0) { + mAnimationStartIndex = childIndex; + } else { + mAnimationStartIndex = Math.min(mAnimationStartIndex, childIndex); + } + } } @Override public void onViewRemoved(View child) { super.onViewRemoved(child); - mIconStates.remove(child); + if (child instanceof StatusBarIconView) { + final StatusBarIconView icon = (StatusBarIconView) child; + if (icon.getVisibleState() != StatusBarIconView.STATE_HIDDEN + && child.getVisibility() == VISIBLE) { + int animationStartIndex = findFirstViewIndexAfter(icon.getTranslationX()); + if (mAnimationStartIndex < 0) { + mAnimationStartIndex = animationStartIndex; + } else { + mAnimationStartIndex = Math.min(mAnimationStartIndex, animationStartIndex); + } + } + if (!mChangingViewPositions) { + mIconStates.remove(child); + addTransientView(icon, 0); + icon.setVisibleState(StatusBarIconView.STATE_HIDDEN, true /* animate */, + () -> removeTransientView(icon)); + } + } + } + + /** + * Finds the first view with a translation bigger then a given value + */ + private int findFirstViewIndexAfter(float translationX) { + for (int i = 0; i < getChildCount(); i++) { + View view = getChildAt(i); + if (view.getTranslationX() > translationX) { + return i; + } + } + return getChildCount(); } public WeakHashMap resetViewStates() { @@ -128,6 +182,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { View view = getChildAt(i); ViewState iconState = mIconStates.get(view); iconState.initFrom(view); + iconState.alpha = 1.0f; } return mIconStates; } @@ -246,21 +301,41 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { return mActualLayoutWidth; } - public static class IconState extends ViewState { + public void setChangingViewPositions(boolean changingViewPositions) { + mChangingViewPositions = changingViewPositions; + } + + public class IconState extends ViewState { public float iconAppearAmount = 1.0f; public int visibleState; + public boolean justAdded = true; @Override public void applyToView(View view) { if (view instanceof StatusBarIconView) { StatusBarIconView icon = (StatusBarIconView) view; - if (visibleState != icon.getVisibleState()) { - icon.setVisibleState(visibleState); - animateTo(icon, DOT_ANIMATION_PROPERTIES); + AnimationProperties animationProperties = DOT_ANIMATION_PROPERTIES; + if (justAdded) { + super.applyToView(icon); + icon.setAlpha(0.0f); + icon.setVisibleState(StatusBarIconView.STATE_HIDDEN, false /* animate */); + animationProperties = ADD_ICON_PROPERTIES; + } + boolean animate = visibleState != icon.getVisibleState() || justAdded; + if (!animate && mAnimationStartIndex >= 0 + && (icon.getVisibleState() != StatusBarIconView.STATE_HIDDEN + || visibleState != StatusBarIconView.STATE_HIDDEN)) { + int viewIndex = indexOfChild(view); + animate = viewIndex >= mAnimationStartIndex; + } + icon.setVisibleState(visibleState); + if (animate) { + animateTo(icon, animationProperties); } else { super.applyToView(view); } } + justAdded = false; } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java index 7c719d8f3fd94..bcd278d762b24 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java @@ -221,7 +221,7 @@ public class ExpandableViewState extends ViewState { // start dark animation expandableView.setDark(this.dark, animationFilter.animateDark, properties.delay); - if (properties.wasAdded(child)) { + if (properties.wasAdded(child) && !hidden) { expandableView.performAddAnimation(properties.delay, properties.duration); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java index 342d307954549..1f29b4fd7d917 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java @@ -372,7 +372,7 @@ public class StackStateAnimator { } else if (event.animationType == NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE) { - if (changingView.getVisibility() == View.GONE) { + if (changingView.getVisibility() != View.VISIBLE) { removeFromOverlay(changingView); continue; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java index 124cabb0770f9..8a5ddd43b24cd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java @@ -210,7 +210,7 @@ public class ViewState { } // start alpha animation - if (alphaChanging && child.getTranslationX() == 0) { + if (alphaChanging) { startAlphaAnimation(child, animationProperties); } else { abortAnimation(child, TAG_ANIMATOR_ALPHA);