summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Selim Cinek <cinek@google.com> 2016-10-21 15:31:26 -0700
committer Selim Cinek <cinek@google.com> 2016-11-21 14:33:45 -0800
commitc383fd0508783cf37e7bb7dde7b3989fceb608e3 (patch)
tree486bebf161f268fed4b69c7bdbfbf0f0db95b601
parent48ff9b48335b6a22795f798ff07c9a6d83078c1c (diff)
Refactored shelf transformation code to support animations
The shelf positions are now applied in each frame if there is an animation in order to not have weird transitions when a notifications moves in / out of the shelf. Test: Add notifications, swipe one away see animation out of the shelf Bug: 32437839 Change-Id: Ie50362c85ec2fb2a9822de6a387167913d7a58dd
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java142
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java3
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) {