Heads up notification can now scroll away after it was seen

Previously it would stick to the top forever, which was very
undesirable and unclear.

Fixes: 	62214133
Test: manual, add multiple huns, nothing sticks to the top
Test: add hun when qs expanded
Change-Id: I3338129ced49dacf01c658767aaedd0f1a408c44
This commit is contained in:
Selim Cinek
2017-11-30 12:29:47 +01:00
parent 05013b3772
commit 9b9d6e16bc
6 changed files with 50 additions and 13 deletions

View File

@@ -112,6 +112,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private int mNotificationMaxHeight;
private int mNotificationAmbientHeight;
private int mIncreasedPaddingBetweenElements;
private boolean mMustStayOnScreen;
/** Does this row contain layouts that can adapt to row expansion */
private boolean mExpandable;
@@ -491,6 +492,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
notifyHeightChanged(false /* needsAnimation */);
}
if (isHeadsUp) {
mMustStayOnScreen = true;
setAboveShelf(true);
} else if (isAboveShelf() != wasAboveShelf) {
mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
@@ -517,6 +519,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
addChildNotification(row, -1);
}
@Override
public void setHeadsUpIsVisible() {
super.setHeadsUpIsVisible();
mMustStayOnScreen = false;
}
/**
* Add a child notification to this view.
*
@@ -1942,7 +1950,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
@Override
public boolean mustStayOnScreen() {
return mIsHeadsUp;
return mIsHeadsUp && mMustStayOnScreen;
}
/**

View File

@@ -478,6 +478,9 @@ public abstract class ExpandableView extends FrameLayout {
return false;
}
public void setHeadsUpIsVisible() {
}
public boolean isChildInGroup() {
return false;
}

View File

@@ -94,6 +94,12 @@ public class ExpandableViewState extends ViewState {
public float shadowAlpha;
public boolean inShelf;
/**
* A state indicating whether a headsup is currently fully visible, even when not scrolled.
* Only valid if the view is heads upped.
*/
public boolean headsUpIsVisible;
/**
* How much the child overlaps with the previous child on top. This is used to
* show the background properly when the child on top is translating away.
@@ -126,6 +132,7 @@ public class ExpandableViewState extends ViewState {
clipTopAmount = svs.clipTopAmount;
notGoneIndex = svs.notGoneIndex;
location = svs.location;
headsUpIsVisible = svs.headsUpIsVisible;
}
}
@@ -175,6 +182,10 @@ public class ExpandableViewState extends ViewState {
expandableView.setTransformingInShelf(false);
expandableView.setInShelf(inShelf);
if (headsUpIsVisible) {
expandableView.setHeadsUpIsVisible();
}
}
}
@@ -229,6 +240,10 @@ public class ExpandableViewState extends ViewState {
expandableView.setTransformingInShelf(true);
}
expandableView.setInShelf(this.inShelf);
if (headsUpIsVisible) {
expandableView.setHeadsUpIsVisible();
}
}
private void startHeightAnimation(final ExpandableView child, AnimationProperties properties) {

View File

@@ -624,7 +624,7 @@ public class NotificationStackScrollLayout extends ViewGroup
if (childViewState == null) {
return false;
}
if ((childViewState.location &= ExpandableViewState.VISIBLE_LOCATIONS) == 0) {
if ((childViewState.location & ExpandableViewState.VISIBLE_LOCATIONS) == 0) {
return false;
}
if (row.getVisibility() != View.VISIBLE) {

View File

@@ -135,7 +135,7 @@ public class StackScrollAlgorithm {
for (int i = 0; i < childCount; i++) {
ExpandableView child = algorithmState.visibleChildren.get(i);
ExpandableViewState state = resultState.getViewStateForView(child);
if (!child.mustStayOnScreen()) {
if (!child.mustStayOnScreen() || state.headsUpIsVisible) {
previousNotificationEnd = Math.max(drawStart, previousNotificationEnd);
previousNotificationStart = Math.max(drawStart, previousNotificationStart);
}
@@ -378,6 +378,13 @@ public class StackScrollAlgorithm {
boolean isEmptyShadeView = child instanceof EmptyShadeView;
childViewState.location = ExpandableViewState.LOCATION_MAIN_AREA;
float inset = ambientState.getTopPadding() + ambientState.getStackTranslation();
if (child.mustStayOnScreen() && childViewState.yTranslation >= 0) {
// Even if we're not scrolled away we're in view and we're also not in the
// shelf. We can relax the constraints and let us scroll off the top!
float end = childViewState.yTranslation + childViewState.height + inset;
childViewState.headsUpIsVisible = end < ambientState.getMaxHeadsUpTranslation();
}
if (isDismissView) {
childViewState.yTranslation = Math.min(childViewState.yTranslation,
ambientState.getInnerHeight() - childHeight);
@@ -396,8 +403,7 @@ public class StackScrollAlgorithm {
Log.wtf(LOG_TAG, "Failed to assign location for child " + i);
}
childViewState.yTranslation += ambientState.getTopPadding()
+ ambientState.getStackTranslation();
childViewState.yTranslation += inset;
return currentYPosition;
}
@@ -420,19 +426,21 @@ public class StackScrollAlgorithm {
break;
}
ExpandableViewState childState = resultState.getViewStateForView(row);
if (topHeadsUpEntry == null) {
if (topHeadsUpEntry == null && row.mustStayOnScreen() && !childState.headsUpIsVisible) {
topHeadsUpEntry = row;
childState.location = ExpandableViewState.LOCATION_FIRST_HUN;
}
boolean isTopEntry = topHeadsUpEntry == row;
float unmodifiedEndLocation = childState.yTranslation + childState.height;
if (mIsExpanded) {
// Ensure that the heads up is always visible even when scrolled off
clampHunToTop(ambientState, row, childState);
if (i == 0 && ambientState.isAboveShelf(row)) {
// the first hun can't get off screen.
clampHunToMaxTranslation(ambientState, row, childState);
childState.hidden = false;
if (row.mustStayOnScreen() && !childState.headsUpIsVisible) {
// Ensure that the heads up is always visible even when scrolled off
clampHunToTop(ambientState, row, childState);
if (i == 0 && ambientState.isAboveShelf(row)) {
// the first hun can't get off screen.
clampHunToMaxTranslation(ambientState, row, childState);
childState.hidden = false;
}
}
}
if (row.isPinned()) {
@@ -493,6 +501,7 @@ public class StackScrollAlgorithm {
if (childViewState.yTranslation >= shelfStart) {
childViewState.hidden = true;
childViewState.inShelf = true;
childViewState.headsUpIsVisible = false;
}
if (!ambientState.isShadeExpanded()) {
childViewState.height = (int) (mStatusBarHeight - childViewState.yTranslation);
@@ -531,7 +540,8 @@ public class StackScrollAlgorithm {
ExpandableViewState childViewState = resultState.getViewStateForView(child);
int zDistanceBetweenElements = ambientState.getZDistanceBetweenElements();
float baseZ = ambientState.getBaseZHeight();
if (child.mustStayOnScreen() && !ambientState.isDozingAndNotPulsing(child)
if (child.mustStayOnScreen() && !childViewState.headsUpIsVisible
&& !ambientState.isDozingAndNotPulsing(child)
&& childViewState.yTranslation < ambientState.getTopPadding()
+ ambientState.getStackTranslation()) {
if (childrenOnTop != 0.0f) {

View File

@@ -84,6 +84,7 @@ public class StackScrollState {
viewState.scaleX = view.getScaleX();
viewState.scaleY = view.getScaleY();
viewState.inShelf = false;
viewState.headsUpIsVisible = false;
}
public ExpandableViewState getViewStateForView(View requestedView) {