Make group expanding nicer
The group expanding now follows the finger.
Bug: 19437552
Change-Id: If85557bb75ea2f2e560cb28d62a06c217187c9c3
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 36090a3..da125d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -869,6 +869,9 @@
public void setUserLocked(boolean userLocked) {
mUserLocked = userLocked;
mPrivateLayout.setUserExpanding(userLocked);
+ if (mIsSummaryWithChildren) {
+ mChildrenContainer.setUserLocked(userLocked);
+ }
}
/**
@@ -1175,6 +1178,9 @@
int contentHeight = Math.max(getMinHeight(), height);
mPrivateLayout.setContentHeight(contentHeight);
mPublicLayout.setContentHeight(contentHeight);
+ if (mIsSummaryWithChildren) {
+ mChildrenContainer.setActualHeight(height);
+ }
if (mGuts != null) {
mGuts.setActualHeight(height);
}
@@ -1260,7 +1266,7 @@
return mMaxExpandHeight != 0;
}
- private NotificationContentView getShowingLayout() {
+ public NotificationContentView getShowingLayout() {
return mShowingPublic ? mPublicLayout : mPrivateLayout;
}
@@ -1296,8 +1302,15 @@
}
@Override
- public boolean needsIncreasedPadding() {
- return mIsSummaryWithChildren && isGroupExpanded();
+ public float getIncreasedPaddingAmount() {
+ if (mIsSummaryWithChildren) {
+ if (isGroupExpanded()) {
+ return 1.0f;
+ } else if (isUserLocked()) {
+ return mChildrenContainer.getChildExpandFraction();
+ }
+ }
+ return 0.0f;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index c9e1cff..1ff87f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -391,8 +391,11 @@
public void setShadowAlpha(float shadowAlpha) {
}
- public boolean needsIncreasedPadding() {
- return false;
+ /**
+ * @return an amount between 0 and 1 of increased padding that this child needs
+ */
+ public float getIncreasedPaddingAmount() {
+ return 0.0f;
}
public boolean mustStayOnScreen() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index fa2608a..977b37e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -401,10 +401,14 @@
}
public int getMinHeight() {
- if (mIsChildInGroup && !isGroupExpanded()) {
- return mSingleLineView.getHeight();
- } else {
+ return getMinHeight(false /* likeGroupExpanded */);
+ }
+
+ public int getMinHeight(boolean likeGroupExpanded) {
+ if (likeGroupExpanded || !mIsChildInGroup || isGroupExpanded()) {
return mContractedChild.getHeight();
+ } else {
+ return mSingleLineView.getHeight();
}
}
@@ -535,8 +539,11 @@
*/
private int calculateVisibleType() {
if (mUserExpanding) {
- int expandedVisualType = getVisualTypeForHeight(
- mContainingNotification.getMaxExpandHeight());
+ int height = !mIsChildInGroup || isGroupExpanded()
+ || mContainingNotification.isExpanded()
+ ? mContainingNotification.getMaxContentHeight()
+ : mContainingNotification.getShowingLayout().getMinHeight();
+ int expandedVisualType = getVisualTypeForHeight(height);
int collapsedVisualType = getVisualTypeForHeight(
mContainingNotification.getMinExpandHeight());
return mTransformationStartVisibleType == collapsedVisualType
@@ -552,7 +559,7 @@
if (!noExpandedChild && viewHeight == mExpandedChild.getHeight()) {
return VISIBLE_TYPE_EXPANDED;
}
- if (mIsChildInGroup && !isGroupExpanded()) {
+ if (!mUserExpanding && mIsChildInGroup && !isGroupExpanded()) {
return VISIBLE_TYPE_SINGLELINE;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index 49aec42..030c8b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -29,6 +29,7 @@
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.HybridNotificationView;
import com.android.systemui.statusbar.notification.HybridNotificationViewManager;
+import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.phone.NotificationPanelView;
import java.util.ArrayList;
@@ -60,6 +61,8 @@
private ViewState mGroupOverFlowState;
private int mRealHeight;
private int mLayoutDirection = LAYOUT_DIRECTION_UNDEFINED;
+ private boolean mUserLocked;
+ private int mActualHeight;
public NotificationChildrenContainer(Context context) {
this(context, null);
@@ -281,27 +284,45 @@
*/
private int getIntrinsicHeight(float maxAllowedVisibleChildren) {
int intrinsicHeight = mNotificationHeaderHeight;
- if (mChildrenExpanded) {
- intrinsicHeight += mNotificatonTopPadding;
- }
int visibleChildren = 0;
int childCount = mChildren.size();
+ boolean firstChild = true;
+ float expandFactor = 0;
+ if (mUserLocked) {
+ expandFactor = getChildExpandFraction();
+ }
for (int i = 0; i < childCount; i++) {
if (visibleChildren >= maxAllowedVisibleChildren) {
break;
}
+ if (!firstChild) {
+ if (mUserLocked) {
+ intrinsicHeight += NotificationUtils.interpolate(mChildPadding, mDividerHeight,
+ expandFactor);
+ } else {
+ intrinsicHeight += mChildrenExpanded ? mDividerHeight : mChildPadding;
+ }
+ } else {
+ if (mUserLocked) {
+ intrinsicHeight += NotificationUtils.interpolate(
+ 0,
+ mNotificatonTopPadding + mDividerHeight,
+ expandFactor);
+ } else {
+ intrinsicHeight += mChildrenExpanded
+ ? mNotificatonTopPadding + mDividerHeight
+ : 0;
+ }
+ firstChild = false;
+ }
ExpandableNotificationRow child = mChildren.get(i);
intrinsicHeight += child.getIntrinsicHeight();
visibleChildren++;
}
- if (visibleChildren > 0) {
- if (mChildrenExpanded) {
- intrinsicHeight += visibleChildren * mDividerHeight;
- } else {
- intrinsicHeight += (visibleChildren - 1) * mChildPadding;
- }
- }
- if (!mChildrenExpanded) {
+ if (mUserLocked) {
+ intrinsicHeight += NotificationUtils.interpolate(mCollapsedBottompadding, 0.0f,
+ expandFactor);
+ } else if (!mChildrenExpanded) {
intrinsicHeight += mCollapsedBottompadding;
}
return intrinsicHeight;
@@ -323,12 +344,28 @@
int lastVisibleIndex = hasOverflow
? maxAllowedVisibleChildren - 2
: maxAllowedVisibleChildren - 1;
+ float expandFactor = 0;
+ if (mUserLocked) {
+ expandFactor = getChildExpandFraction();
+ }
for (int i = 0; i < childCount; i++) {
ExpandableNotificationRow child = mChildren.get(i);
if (!firstChild) {
- yPosition += mChildrenExpanded ? mDividerHeight : mChildPadding;
+ if (mUserLocked) {
+ yPosition += NotificationUtils.interpolate(mChildPadding, mDividerHeight,
+ expandFactor);
+ } else {
+ yPosition += mChildrenExpanded ? mDividerHeight : mChildPadding;
+ }
} else {
- yPosition += mChildrenExpanded ? mNotificatonTopPadding + mDividerHeight : 0;
+ if (mUserLocked) {
+ yPosition += NotificationUtils.interpolate(
+ 0,
+ mNotificatonTopPadding + mDividerHeight,
+ expandFactor);
+ } else {
+ yPosition += mChildrenExpanded ? mNotificatonTopPadding + mDividerHeight : 0;
+ }
firstChild = false;
}
StackViewState childState = resultState.getViewStateForView(child);
@@ -375,6 +412,7 @@
public void applyState(StackScrollState state) {
int childCount = mChildren.size();
ViewState tmpState = new ViewState();
+ float expandFraction = getChildExpandFraction();
for (int i = 0; i < childCount; i++) {
ExpandableNotificationRow child = mChildren.get(i);
StackViewState viewState = state.getViewStateForView(child);
@@ -384,7 +422,11 @@
View divider = mDividers.get(i);
tmpState.initFrom(divider);
tmpState.yTranslation = viewState.yTranslation - mDividerHeight;
- tmpState.alpha = mChildrenExpanded && viewState.alpha != 0 ? 0.5f : 0;
+ float alpha = mChildrenExpanded && viewState.alpha != 0 ? 0.5f : 0;
+ if (mUserLocked && viewState.alpha != 0) {
+ alpha = NotificationUtils.interpolate(0, 0.5f, expandFraction);
+ }
+ tmpState.alpha = alpha;
state.applyViewState(divider, tmpState);
}
if (mGroupOverflowContainer != null) {
@@ -407,6 +449,7 @@
long baseDelay, long duration) {
int childCount = mChildren.size();
ViewState tmpState = new ViewState();
+ float expandFraction = getChildExpandFraction();
for (int i = childCount - 1; i >= 0; i--) {
ExpandableNotificationRow child = mChildren.get(i);
StackViewState viewState = state.getViewStateForView(child);
@@ -416,7 +459,11 @@
View divider = mDividers.get(i);
tmpState.initFrom(divider);
tmpState.yTranslation = viewState.yTranslation - mDividerHeight;
- tmpState.alpha = mChildrenExpanded && viewState.alpha != 0 ? 0.5f : 0;
+ float alpha = mChildrenExpanded && viewState.alpha != 0 ? 0.5f : 0;
+ if (mUserLocked && viewState.alpha != 0) {
+ alpha = NotificationUtils.interpolate(0, 0.5f, expandFraction);
+ }
+ tmpState.alpha = alpha;
stateAnimator.startViewAnimations(divider, tmpState, baseDelay, duration);
}
if (mGroupOverflowContainer != null) {
@@ -449,7 +496,70 @@
}
public int getMaxContentHeight() {
- return getIntrinsicHeight(NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED);
+ int maxContentHeight = mNotificationHeaderHeight + mNotificatonTopPadding;
+ int visibleChildren = 0;
+ int childCount = mChildren.size();
+ for (int i = 0; i < childCount; i++) {
+ if (visibleChildren >= NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED) {
+ break;
+ }
+ ExpandableNotificationRow child = mChildren.get(i);
+ float childHeight = child.isExpanded()
+ ? child.getMaxExpandHeight()
+ : child.getShowingLayout().getMinHeight(true /* likeGroupExpanded */);
+ maxContentHeight += childHeight;
+ visibleChildren++;
+ }
+ if (visibleChildren > 0) {
+ maxContentHeight += visibleChildren * mDividerHeight;
+ }
+ return maxContentHeight;
+ }
+
+ public void setActualHeight(int actualHeight) {
+ if (!mUserLocked) {
+ return;
+ }
+ mActualHeight = actualHeight;
+ float fraction = getChildExpandFraction();
+ int childCount = mChildren.size();
+ for (int i = 0; i < childCount; i++) {
+ ExpandableNotificationRow child = mChildren.get(i);
+ float childHeight = child.isExpanded()
+ ? child.getMaxExpandHeight()
+ : child.getShowingLayout().getMinHeight(true /* likeGroupExpanded */);
+ float singleLineHeight = child.getShowingLayout().getMinHeight(
+ false /* likeGroupExpanded */);
+ child.setActualHeight((int) NotificationUtils.interpolate(singleLineHeight, childHeight,
+ fraction), false);
+ }
+ }
+
+ public float getChildExpandFraction() {
+ int allChildrenVisibleHeight = getChildrenExpandStartHeight();
+ int maxContentHeight = getMaxContentHeight();
+ float factor = (mActualHeight - allChildrenVisibleHeight)
+ / (float) (maxContentHeight - allChildrenVisibleHeight);
+ return Math.max(0.0f, Math.min(1.0f, factor));
+ }
+
+ private int getChildrenExpandStartHeight() {
+ int intrinsicHeight = mNotificationHeaderHeight;
+ int visibleChildren = 0;
+ int childCount = mChildren.size();
+ for (int i = 0; i < childCount; i++) {
+ if (visibleChildren >= NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED) {
+ break;
+ }
+ ExpandableNotificationRow child = mChildren.get(i);
+ intrinsicHeight += child.getMinHeight();
+ visibleChildren++;
+ }
+ if (visibleChildren > 0) {
+ intrinsicHeight += (visibleChildren - 1) * mChildPadding;
+ }
+ intrinsicHeight += mCollapsedBottompadding;
+ return intrinsicHeight;
}
public int getMinHeight() {
@@ -477,4 +587,13 @@
mDividers.set(i, divider);
}
}
+
+ public void setUserLocked(boolean userLocked) {
+ mUserLocked = userLocked;
+ int childCount = mChildren.size();
+ for (int i = 0; i < childCount; i++) {
+ ExpandableNotificationRow child = mChildren.get(i);
+ child.setUserLocked(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 fe06c3a..e1f9f3c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -64,6 +64,7 @@
import com.android.systemui.statusbar.StackScrollerDecorView;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.FakeShadowView;
+import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.phone.ScrimController;
@@ -538,7 +539,7 @@
ExpandableView child = (ExpandableView) getChildAt(i);
if (mChildrenToAddAnimated.contains(child)) {
int startingPosition = getPositionInLinearLayout(child);
- int padding = child.needsIncreasedPadding()
+ int padding = child.getIncreasedPaddingAmount() == 1.0f
? mIncreasedPaddingBetweenElements :
mPaddingBetweenElements;
int childHeight = getIntrinsicHeight(child) + padding;
@@ -1531,18 +1532,18 @@
private void updateContentHeight() {
int height = 0;
- boolean previousNeedsIncreasedPaddings = false;
+ float previousIncreasedAmount = 0.0f;
for (int i = 0; i < getChildCount(); i++) {
ExpandableView expandableView = (ExpandableView) getChildAt(i);
if (expandableView.getVisibility() != View.GONE) {
- boolean needsIncreasedPaddings = expandableView.needsIncreasedPadding();
+ float increasedPaddingAmount = expandableView.getIncreasedPaddingAmount();
if (height != 0) {
- int padding = needsIncreasedPaddings || previousNeedsIncreasedPaddings
- ? mIncreasedPaddingBetweenElements
- : mPaddingBetweenElements;
- height += padding;
+ height += (int) NotificationUtils.interpolate(
+ mPaddingBetweenElements,
+ mIncreasedPaddingBetweenElements,
+ Math.max(previousIncreasedAmount, increasedPaddingAmount));
}
- previousNeedsIncreasedPaddings = needsIncreasedPaddings;
+ previousIncreasedAmount = increasedPaddingAmount;
height += expandableView.getIntrinsicHeight();
}
}
@@ -2097,9 +2098,10 @@
*/
private void updateScrollStateForRemovedChild(ExpandableView removedChild) {
int startingPosition = getPositionInLinearLayout(removedChild);
- int padding = removedChild.needsIncreasedPadding()
- ? mIncreasedPaddingBetweenElements :
- mPaddingBetweenElements;
+ int padding = (int) NotificationUtils.interpolate(
+ mPaddingBetweenElements,
+ mIncreasedPaddingBetweenElements,
+ removedChild.getIncreasedPaddingAmount());
int childHeight = getIntrinsicHeight(removedChild) + padding;
int endPosition = startingPosition + childHeight;
if (endPosition <= mOwnScrollY) {
@@ -2123,19 +2125,19 @@
private int getPositionInLinearLayout(View requestedChild) {
int position = 0;
- boolean previousNeedsIncreasedPaddings = false;
+ float previousIncreasedAmount = 0.0f;
for (int i = 0; i < getChildCount(); i++) {
ExpandableView child = (ExpandableView) getChildAt(i);
boolean notGone = child.getVisibility() != View.GONE;
if (notGone) {
- boolean needsIncreasedPaddings = child.needsIncreasedPadding();
+ float increasedPaddingAmount = child.getIncreasedPaddingAmount();
if (position != 0) {
- int padding = needsIncreasedPaddings || previousNeedsIncreasedPaddings
- ? mIncreasedPaddingBetweenElements :
- mPaddingBetweenElements;
- position += padding;
+ position += (int) NotificationUtils.interpolate(
+ mPaddingBetweenElements,
+ mIncreasedPaddingBetweenElements,
+ Math.max(previousIncreasedAmount, increasedPaddingAmount));
}
- previousNeedsIncreasedPaddings = needsIncreasedPaddings;
+ previousIncreasedAmount = increasedPaddingAmount;
}
if (child == requestedChild) {
return position;
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 d78d626..eea923f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -25,9 +25,10 @@
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.notification.FakeShadowView;
+import com.android.systemui.statusbar.notification.NotificationUtils;
import java.util.ArrayList;
-import java.util.HashSet;
+import java.util.HashMap;
import java.util.List;
/**
@@ -297,18 +298,22 @@
int childCount = hostView.getChildCount();
state.visibleChildren.clear();
state.visibleChildren.ensureCapacity(childCount);
- state.increasedPaddingSet.clear();
+ state.increasedPaddingMap.clear();
int notGoneIndex = 0;
ExpandableView lastView = null;
for (int i = 0; i < childCount; i++) {
ExpandableView v = (ExpandableView) hostView.getChildAt(i);
if (v.getVisibility() != View.GONE) {
notGoneIndex = updateNotGoneIndex(resultState, state, notGoneIndex, v);
- boolean needsIncreasedPadding = v.needsIncreasedPadding();
- if (needsIncreasedPadding) {
- state.increasedPaddingSet.add(v);
+ float increasedPadding = v.getIncreasedPaddingAmount();
+ if (increasedPadding != 0.0f) {
+ state.increasedPaddingMap.put(v, increasedPadding);
if (lastView != null) {
- state.increasedPaddingSet.add(lastView);
+ Float prevValue = state.increasedPaddingMap.get(lastView);
+ float newValue = prevValue != null
+ ? Math.max(prevValue, increasedPadding)
+ : increasedPadding;
+ state.increasedPaddingMap.put(lastView, newValue);
}
}
if (v instanceof ExpandableNotificationRow) {
@@ -423,9 +428,12 @@
private int getPaddingAfterChild(StackScrollAlgorithmState algorithmState,
ExpandableView child) {
- return algorithmState.increasedPaddingSet.contains(child)
- ? mIncreasedPaddingBetweenElements
- : mPaddingBetweenElements;
+ Float paddingValue = algorithmState.increasedPaddingMap.get(child);
+ return paddingValue == null
+ ? mPaddingBetweenElements
+ : (int) NotificationUtils.interpolate(mPaddingBetweenElements,
+ mIncreasedPaddingBetweenElements,
+ paddingValue);
}
private void updateHeadsUpStates(StackScrollState resultState,
@@ -765,9 +773,10 @@
public final ArrayList<ExpandableView> visibleChildren = new ArrayList<ExpandableView>();
/**
- * The children from the host that need an increased padding after them.
+ * The children from the host that need an increased padding after them. A value of 0 means
+ * no increased padding, a value of 1 means full padding.
*/
- public final HashSet<ExpandableView> increasedPaddingSet = new HashSet<>();
+ public final HashMap<ExpandableView, Float> increasedPaddingMap = new HashMap<>();
}
}