diff options
5 files changed, 116 insertions, 98 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java index 9fd0e4c54d40..bba411c3f99a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java @@ -1765,7 +1765,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { public static class NotificationViewState extends ExpandableViewState { private final StackScrollState mOverallState; - public float iconTransformationAmount; private NotificationViewState(StackScrollState stackScrollState) { @@ -1781,7 +1780,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { row.setClipToActualHeight(true); } row.applyChildrenState(mOverallState); - row.setIconTransformationAmount(iconTransformationAmount); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index ff644ea10171..8a6ce56913b3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -16,6 +16,8 @@ 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; @@ -29,9 +31,9 @@ import com.android.systemui.statusbar.phone.NotificationIconContainer; import com.android.systemui.statusbar.phone.NotificationPanelView; import com.android.systemui.statusbar.stack.AmbientState; import com.android.systemui.statusbar.stack.ExpandableViewState; +import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.stack.StackScrollAlgorithm; import com.android.systemui.statusbar.stack.StackScrollState; -import com.android.systemui.statusbar.stack.ViewState; import java.util.ArrayList; import java.util.WeakHashMap; @@ -52,6 +54,8 @@ public class NotificationShelf extends ActivatableNotificationView { private int mIconAppearTopPadding; private int mStatusBarHeight; private int mStatusBarPaddingStart; + private AmbientState mAmbientState; + private NotificationStackScrollLayout mHostLayout; public NotificationShelf(Context context, AttributeSet attrs) { super(context, attrs); @@ -70,10 +74,14 @@ public class NotificationShelf extends ActivatableNotificationView { mViewInvertHelper = new ViewInvertHelper(mNotificationIconContainer, NotificationPanelView.DOZE_ANIMATION_DURATION); mShelfState = new ShelfState(); - mShelfState.iconStates = mNotificationIconContainer.getIconStates(); initDimens(); } + public void bind(AmbientState ambientState, NotificationStackScrollLayout hostLayout) { + mAmbientState = ambientState; + mHostLayout = hostLayout; + } + private void initDimens() { mIconAppearTopPadding = getResources().getDimensionPixelSize( R.dimen.notification_icon_appear_padding); @@ -140,60 +148,63 @@ public class NotificationShelf extends ActivatableNotificationView { mShelfState.shadowAlpha = 1.0f; mShelfState.isBottomClipped = false; mShelfState.hideSensitive = false; - - mShelfState.resetIcons(); - float numIconsInShelf = 0.0f; - float viewStart; - float maxShelfStart = maxShelfEnd - mShelfState.height; - // find the first view that doesn't overlap with the shelf - for (int i = shelfIndex; i >= 0; i--) { - lastView = algorithmState.visibleChildren.get(i); - lastViewState = resultState.getViewStateForView(lastView); - ExpandableNotificationRow row = null; - if (lastView instanceof ExpandableNotificationRow) { - row = (ExpandableNotificationRow) lastView; - } - viewStart = lastViewState.yTranslation; - viewEnd = viewStart + lastView.getIntrinsicHeight(); - if (viewEnd > maxShelfStart) { - if (viewStart < maxShelfStart) { - float transitionAmount = 1.0f - ((maxShelfStart - viewStart) / - lastView.getIntrinsicHeight()); - numIconsInShelf += transitionAmount; - } else { - numIconsInShelf += 1.0f; - lastViewState.hidden = true; - } - } - if (row != null){ - // Not in the shelf yet, Icon needs to be placed on top of the notification icon - updateIconAppearance(row.getEntry(), - (ExpandableNotificationRow.NotificationViewState) lastViewState, - mShelfState); - } - } - mShelfState.iconStates = mNotificationIconContainer.calculateIconStates( - numIconsInShelf); - mShelfState.hidden = numIconsInShelf == 0.0f; - mShelfState.hideBackground = numIconsInShelf < 1.0f; } else { - mShelfState.hideBackground = true; mShelfState.hidden = true; mShelfState.location = ExpandableViewState.LOCATION_GONE; } } - private float getFullyClosedTranslation() { - return - (getIntrinsicHeight() - mStatusBarHeight) / 2; + /** + * Update the shelf appearance based on the other notifications around it. This transforms + * the icons from the notification area into the shelf. + */ + public void updateAppearance() { + WeakHashMap<View, IconState> iconStates = + mNotificationIconContainer.resetViewStates(); + float numIconsInShelf = 0.0f; + float maxShelfStart = getTranslationY(); + int shelfIndex = mAmbientState.getShelfIndex() - 1; + // find the first view that doesn't overlap with the shelf + for (int i = shelfIndex; i >= 0; i--) { + ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i); + if (!(child instanceof ExpandableNotificationRow) + || child.getVisibility() == GONE) { + continue; + } + ExpandableNotificationRow row = (ExpandableNotificationRow) child; + StatusBarIconView icon = row.getEntry().expandedIcon; + IconState iconState = iconStates.get(icon); + updateIconAppearance(maxShelfStart, row, iconState, icon); + numIconsInShelf += iconState.iconAppearAmount; + } + mNotificationIconContainer.calculateIconTranslations(); + mNotificationIconContainer.applyIconStates(); + setVisibility(numIconsInShelf == 0.0f ? INVISIBLE : VISIBLE); + setHideBackground(numIconsInShelf < 1.0f); } - private void updateIconAppearance(NotificationData.Entry entry, - ExpandableNotificationRow.NotificationViewState rowState, - ShelfState shelfState) { - StatusBarIconView icon = entry.expandedIcon; - ViewState iconState = shelfState.iconStates.get(icon); - View rowIcon = entry.row.getNotificationIcon(); - float notificationIconPosition = rowState.yTranslation; + private void updateIconAppearance(float maxShelfStart, ExpandableNotificationRow row, + IconState iconState, StatusBarIconView icon) { + + // Let calculate how much the view is in the shelf + float viewStart = row.getTranslationY(); + float viewEnd = viewStart + row.getIntrinsicHeight(); + if (viewEnd > maxShelfStart) { + if (viewStart < maxShelfStart) { + iconState.iconAppearAmount = 1.0f - ((maxShelfStart - viewStart) / + row.getIntrinsicHeight()); + } else { + iconState.iconAppearAmount = 1.0f; + } + } else { + iconState.iconAppearAmount = 0.0f; + } + + // Lets now calculate how much of the transformation has already happened. This is different + // from the above, since we only start transforming when the view is already quite a bit + // pushed in. + View rowIcon = row.getNotificationIcon(); + float notificationIconPosition = viewStart; float notificationIconSize = 0.0f; int iconTopPadding; if (rowIcon != null) { @@ -203,31 +214,39 @@ public class NotificationShelf extends ActivatableNotificationView { iconTopPadding = mIconAppearTopPadding; } notificationIconPosition += iconTopPadding; - float shelfIconPosition = mShelfState.yTranslation + icon.getTop(); + float shelfIconPosition = getTranslationY() + icon.getTop(); shelfIconPosition += ((1.0f - icon.getIconScale()) * icon.getHeight()) / 2.0f; float transitionDistance = getIntrinsicHeight() * 1.5f; - float transformationStartPosition = mShelfState.yTranslation - transitionDistance; + float transformationStartPosition = getTranslationY() - transitionDistance; float transitionAmount = 0.0f; - if (rowState.yTranslation < transformationStartPosition) { + if (viewStart < transformationStartPosition) { // We simply place it on the icon of the notification iconState.yTranslation = notificationIconPosition - shelfIconPosition; } else { - transitionAmount = (rowState.yTranslation - transformationStartPosition) + transitionAmount = (viewStart - transformationStartPosition) / transitionDistance; float startPosition = transformationStartPosition + iconTopPadding; iconState.yTranslation = NotificationUtils.interpolate( startPosition - shelfIconPosition, 0, transitionAmount); } float shelfIconSize = icon.getHeight() * icon.getIconScale(); - Float newSize = NotificationUtils.interpolate(notificationIconSize, shelfIconSize, + if (!row.isShowingIcon()) { + // The view currently doesn't have an icon, lets transform it in! + iconState.alpha = transitionAmount; + notificationIconSize = shelfIconSize / 2.0f; + } + // The notification size is different from the size in the shelf / statusbar + float newSize = NotificationUtils.interpolate(notificationIconSize, shelfIconSize, transitionAmount); iconState.scaleX = newSize / icon.getHeight(); iconState.scaleY = iconState.scaleX; iconState.hidden = transitionAmount == 0.0f; - rowState.iconTransformationAmount = transitionAmount; - if (!entry.row.isShowingIcon()) { - iconState.alpha = transitionAmount; - } + row.setIconTransformationAmount(transitionAmount); + icon.setVisibility(transitionAmount == 0.0f ? INVISIBLE : VISIBLE); + } + + private float getFullyClosedTranslation() { + return - (getIntrinsicHeight() - mStatusBarHeight) / 2; } private int getIconTopPadding(View icon) { @@ -273,20 +292,13 @@ public class NotificationShelf extends ActivatableNotificationView { } private class ShelfState extends ExpandableViewState { - private WeakHashMap<View, ViewState> iconStates = new WeakHashMap<>(); - private boolean hideBackground; private float iconContainerTranslation; @Override public void applyToView(View view) { super.applyToView(view); - mNotificationIconContainer.applyIconStates(iconStates); - setHideBackground(hideBackground); + updateAppearance(); setIconContainerTranslation(iconContainerTranslation); } - - public void resetIcons() { - mNotificationIconContainer.resetViewStates(iconStates); - } } } 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 bf7886d93a3e..11563d5945cd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java @@ -34,7 +34,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { private boolean mShowAllIcons = true; private int mIconTint; - private WeakHashMap<View, ViewState> mIconStates = new WeakHashMap<>(); + private WeakHashMap<View, IconState> mIconStates = new WeakHashMap<>(); public NotificationIconContainer(Context context, AttributeSet attrs) { super(context, attrs); @@ -54,16 +54,16 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { child.layout(0, top, width, top + height); } if (mShowAllIcons) { - resetViewStates(mIconStates); - calculateIconStates(getChildCount()); - applyIconStates(mIconStates); + resetViewStates(); + calculateIconTranslations(); + applyIconStates(); } } - public void applyIconStates(WeakHashMap<View, ViewState> iconStates) { + public void applyIconStates() { for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); - ViewState childState = iconStates.get(child); + ViewState childState = mIconStates.get(child); if (childState != null) { childState.applyToView(child); } @@ -73,7 +73,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { @Override public void onViewAdded(View child) { super.onViewAdded(child); - mIconStates.put(child, new ViewState()); + mIconStates.put(child, new IconState()); } @Override @@ -86,42 +86,33 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { mIconTint = iconTint; } - public void resetViewStates(WeakHashMap<View, ViewState> viewStates) { + public WeakHashMap<View, IconState> resetViewStates() { for (int i = 0; i < getChildCount(); i++) { View view = getChildAt(i); ViewState iconState = mIconStates.get(view); iconState.initFrom(view); } + return mIconStates; } /** - * Gets a new state based on the number of visible icons starting from the right. + * Calulate the horizontal translations for each notification based on how much the icons + * are inserted into the notification container. * If this is not a whole number, the fraction means by how much the icon is appearing. */ - public WeakHashMap<View, ViewState> calculateIconStates(float numberOfVisibleIcons) { + public WeakHashMap<View, IconState> calculateIconTranslations() { int childCount = getChildCount(); float visibleIconStart = childCount - numberOfVisibleIcons; - int firstIconIndex = (int) visibleIconStart; float translationX = 0.0f; for (int i = 0; i < childCount; i++) { View view = getChildAt(i); - ViewState iconState = mIconStates.get(view); - if (i >= firstIconIndex) { - iconState.xTranslation = translationX; - float appearAmount = 1.0f; - if (i == firstIconIndex) { - appearAmount = 1.0f - (visibleIconStart - firstIconIndex); - } - translationX += appearAmount * view.getWidth(); - } + IconState iconState = mIconStates.get(view); + iconState.xTranslation = translationX; + translationX += iconState.iconAppearAmount * view.getWidth(); } return mIconStates; } - public WeakHashMap<View, ViewState> getIconStates() { - return mIconStates; - } - /** * Sets whether the layout should always show all icons. * If this is true, the icon positions will be updated on layout. @@ -131,4 +122,13 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { public void setShowAllIcons(boolean showAllIcons) { mShowAllIcons = showAllIcons; } + + public static class IconState extends ViewState { + public float iconAppearAmount = 1.0f; + + @Override + public void applyToView(View view) { + super.applyToView(view); + } + } } 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 d04672338027..d35e4a5d6b47 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -264,14 +264,11 @@ public class NotificationStackScrollLayout extends ViewGroup private final ArrayList<Pair<ExpandableNotificationRow, Boolean>> mTmpList = new ArrayList<>(); private FalsingManager mFalsingManager; private boolean mAnimationRunning; - private ViewTreeObserver.OnPreDrawListener mBackgroundUpdater + private ViewTreeObserver.OnPreDrawListener mRunningAnimationUpdater = new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { - // if it needs animation - if (!mNeedsAnimation && !mChildrenUpdateRequested) { - updateBackground(); - } + onPreDrawDuringAnimation(); return true; } }; @@ -594,6 +591,13 @@ public class NotificationStackScrollLayout extends ViewGroup } } + private void onPreDrawDuringAnimation() { + if (!mNeedsAnimation && !mChildrenUpdateRequested) { + updateBackground(); + } + mShelf.updateAppearance(); + } + private void updateScrollStateForAddedChildren() { if (mChildrenToAddAnimated.isEmpty()) { return; @@ -3873,9 +3877,9 @@ public class NotificationStackScrollLayout extends ViewGroup public void setAnimationRunning(boolean animationRunning) { if (animationRunning != mAnimationRunning) { if (animationRunning) { - getViewTreeObserver().addOnPreDrawListener(mBackgroundUpdater); + getViewTreeObserver().addOnPreDrawListener(mRunningAnimationUpdater); } else { - getViewTreeObserver().removeOnPreDrawListener(mBackgroundUpdater); + getViewTreeObserver().removeOnPreDrawListener(mRunningAnimationUpdater); } mAnimationRunning = animationRunning; updateContinuousShadowDrawing(); @@ -3950,6 +3954,7 @@ public class NotificationStackScrollLayout extends ViewGroup } addView(mShelf, index); mAmbientState.setShelf(shelf); + shelf.bind(mAmbientState, this); } public NotificationShelf getNotificationShelf() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java index 1b3afe76f1b9..8b40188b2841 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java @@ -506,6 +506,9 @@ public class StackScrollAlgorithm { } childViewState.height = (int) newHeight; } + if (childViewState.yTranslation >= shelfStart) { + childViewState.hidden = true; + } } protected int getMaxAllowedChildHeight(View child) { |