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:
@@ -112,6 +112,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
private int mNotificationMaxHeight;
|
private int mNotificationMaxHeight;
|
||||||
private int mNotificationAmbientHeight;
|
private int mNotificationAmbientHeight;
|
||||||
private int mIncreasedPaddingBetweenElements;
|
private int mIncreasedPaddingBetweenElements;
|
||||||
|
private boolean mMustStayOnScreen;
|
||||||
|
|
||||||
/** Does this row contain layouts that can adapt to row expansion */
|
/** Does this row contain layouts that can adapt to row expansion */
|
||||||
private boolean mExpandable;
|
private boolean mExpandable;
|
||||||
@@ -491,6 +492,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
notifyHeightChanged(false /* needsAnimation */);
|
notifyHeightChanged(false /* needsAnimation */);
|
||||||
}
|
}
|
||||||
if (isHeadsUp) {
|
if (isHeadsUp) {
|
||||||
|
mMustStayOnScreen = true;
|
||||||
setAboveShelf(true);
|
setAboveShelf(true);
|
||||||
} else if (isAboveShelf() != wasAboveShelf) {
|
} else if (isAboveShelf() != wasAboveShelf) {
|
||||||
mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
|
mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
|
||||||
@@ -517,6 +519,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
addChildNotification(row, -1);
|
addChildNotification(row, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setHeadsUpIsVisible() {
|
||||||
|
super.setHeadsUpIsVisible();
|
||||||
|
mMustStayOnScreen = false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a child notification to this view.
|
* Add a child notification to this view.
|
||||||
*
|
*
|
||||||
@@ -1942,7 +1950,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean mustStayOnScreen() {
|
public boolean mustStayOnScreen() {
|
||||||
return mIsHeadsUp;
|
return mIsHeadsUp && mMustStayOnScreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -478,6 +478,9 @@ public abstract class ExpandableView extends FrameLayout {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setHeadsUpIsVisible() {
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isChildInGroup() {
|
public boolean isChildInGroup() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,6 +94,12 @@ public class ExpandableViewState extends ViewState {
|
|||||||
public float shadowAlpha;
|
public float shadowAlpha;
|
||||||
public boolean inShelf;
|
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
|
* 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.
|
* show the background properly when the child on top is translating away.
|
||||||
@@ -126,6 +132,7 @@ public class ExpandableViewState extends ViewState {
|
|||||||
clipTopAmount = svs.clipTopAmount;
|
clipTopAmount = svs.clipTopAmount;
|
||||||
notGoneIndex = svs.notGoneIndex;
|
notGoneIndex = svs.notGoneIndex;
|
||||||
location = svs.location;
|
location = svs.location;
|
||||||
|
headsUpIsVisible = svs.headsUpIsVisible;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,6 +182,10 @@ public class ExpandableViewState extends ViewState {
|
|||||||
|
|
||||||
expandableView.setTransformingInShelf(false);
|
expandableView.setTransformingInShelf(false);
|
||||||
expandableView.setInShelf(inShelf);
|
expandableView.setInShelf(inShelf);
|
||||||
|
|
||||||
|
if (headsUpIsVisible) {
|
||||||
|
expandableView.setHeadsUpIsVisible();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,6 +240,10 @@ public class ExpandableViewState extends ViewState {
|
|||||||
expandableView.setTransformingInShelf(true);
|
expandableView.setTransformingInShelf(true);
|
||||||
}
|
}
|
||||||
expandableView.setInShelf(this.inShelf);
|
expandableView.setInShelf(this.inShelf);
|
||||||
|
|
||||||
|
if (headsUpIsVisible) {
|
||||||
|
expandableView.setHeadsUpIsVisible();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startHeightAnimation(final ExpandableView child, AnimationProperties properties) {
|
private void startHeightAnimation(final ExpandableView child, AnimationProperties properties) {
|
||||||
|
|||||||
@@ -624,7 +624,7 @@ public class NotificationStackScrollLayout extends ViewGroup
|
|||||||
if (childViewState == null) {
|
if (childViewState == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ((childViewState.location &= ExpandableViewState.VISIBLE_LOCATIONS) == 0) {
|
if ((childViewState.location & ExpandableViewState.VISIBLE_LOCATIONS) == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (row.getVisibility() != View.VISIBLE) {
|
if (row.getVisibility() != View.VISIBLE) {
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ public class StackScrollAlgorithm {
|
|||||||
for (int i = 0; i < childCount; i++) {
|
for (int i = 0; i < childCount; i++) {
|
||||||
ExpandableView child = algorithmState.visibleChildren.get(i);
|
ExpandableView child = algorithmState.visibleChildren.get(i);
|
||||||
ExpandableViewState state = resultState.getViewStateForView(child);
|
ExpandableViewState state = resultState.getViewStateForView(child);
|
||||||
if (!child.mustStayOnScreen()) {
|
if (!child.mustStayOnScreen() || state.headsUpIsVisible) {
|
||||||
previousNotificationEnd = Math.max(drawStart, previousNotificationEnd);
|
previousNotificationEnd = Math.max(drawStart, previousNotificationEnd);
|
||||||
previousNotificationStart = Math.max(drawStart, previousNotificationStart);
|
previousNotificationStart = Math.max(drawStart, previousNotificationStart);
|
||||||
}
|
}
|
||||||
@@ -378,6 +378,13 @@ public class StackScrollAlgorithm {
|
|||||||
boolean isEmptyShadeView = child instanceof EmptyShadeView;
|
boolean isEmptyShadeView = child instanceof EmptyShadeView;
|
||||||
|
|
||||||
childViewState.location = ExpandableViewState.LOCATION_MAIN_AREA;
|
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) {
|
if (isDismissView) {
|
||||||
childViewState.yTranslation = Math.min(childViewState.yTranslation,
|
childViewState.yTranslation = Math.min(childViewState.yTranslation,
|
||||||
ambientState.getInnerHeight() - childHeight);
|
ambientState.getInnerHeight() - childHeight);
|
||||||
@@ -396,8 +403,7 @@ public class StackScrollAlgorithm {
|
|||||||
Log.wtf(LOG_TAG, "Failed to assign location for child " + i);
|
Log.wtf(LOG_TAG, "Failed to assign location for child " + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
childViewState.yTranslation += ambientState.getTopPadding()
|
childViewState.yTranslation += inset;
|
||||||
+ ambientState.getStackTranslation();
|
|
||||||
return currentYPosition;
|
return currentYPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,13 +426,14 @@ public class StackScrollAlgorithm {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ExpandableViewState childState = resultState.getViewStateForView(row);
|
ExpandableViewState childState = resultState.getViewStateForView(row);
|
||||||
if (topHeadsUpEntry == null) {
|
if (topHeadsUpEntry == null && row.mustStayOnScreen() && !childState.headsUpIsVisible) {
|
||||||
topHeadsUpEntry = row;
|
topHeadsUpEntry = row;
|
||||||
childState.location = ExpandableViewState.LOCATION_FIRST_HUN;
|
childState.location = ExpandableViewState.LOCATION_FIRST_HUN;
|
||||||
}
|
}
|
||||||
boolean isTopEntry = topHeadsUpEntry == row;
|
boolean isTopEntry = topHeadsUpEntry == row;
|
||||||
float unmodifiedEndLocation = childState.yTranslation + childState.height;
|
float unmodifiedEndLocation = childState.yTranslation + childState.height;
|
||||||
if (mIsExpanded) {
|
if (mIsExpanded) {
|
||||||
|
if (row.mustStayOnScreen() && !childState.headsUpIsVisible) {
|
||||||
// Ensure that the heads up is always visible even when scrolled off
|
// Ensure that the heads up is always visible even when scrolled off
|
||||||
clampHunToTop(ambientState, row, childState);
|
clampHunToTop(ambientState, row, childState);
|
||||||
if (i == 0 && ambientState.isAboveShelf(row)) {
|
if (i == 0 && ambientState.isAboveShelf(row)) {
|
||||||
@@ -435,6 +442,7 @@ public class StackScrollAlgorithm {
|
|||||||
childState.hidden = false;
|
childState.hidden = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (row.isPinned()) {
|
if (row.isPinned()) {
|
||||||
childState.yTranslation = Math.max(childState.yTranslation, 0);
|
childState.yTranslation = Math.max(childState.yTranslation, 0);
|
||||||
childState.height = Math.max(row.getIntrinsicHeight(), childState.height);
|
childState.height = Math.max(row.getIntrinsicHeight(), childState.height);
|
||||||
@@ -493,6 +501,7 @@ public class StackScrollAlgorithm {
|
|||||||
if (childViewState.yTranslation >= shelfStart) {
|
if (childViewState.yTranslation >= shelfStart) {
|
||||||
childViewState.hidden = true;
|
childViewState.hidden = true;
|
||||||
childViewState.inShelf = true;
|
childViewState.inShelf = true;
|
||||||
|
childViewState.headsUpIsVisible = false;
|
||||||
}
|
}
|
||||||
if (!ambientState.isShadeExpanded()) {
|
if (!ambientState.isShadeExpanded()) {
|
||||||
childViewState.height = (int) (mStatusBarHeight - childViewState.yTranslation);
|
childViewState.height = (int) (mStatusBarHeight - childViewState.yTranslation);
|
||||||
@@ -531,7 +540,8 @@ public class StackScrollAlgorithm {
|
|||||||
ExpandableViewState childViewState = resultState.getViewStateForView(child);
|
ExpandableViewState childViewState = resultState.getViewStateForView(child);
|
||||||
int zDistanceBetweenElements = ambientState.getZDistanceBetweenElements();
|
int zDistanceBetweenElements = ambientState.getZDistanceBetweenElements();
|
||||||
float baseZ = ambientState.getBaseZHeight();
|
float baseZ = ambientState.getBaseZHeight();
|
||||||
if (child.mustStayOnScreen() && !ambientState.isDozingAndNotPulsing(child)
|
if (child.mustStayOnScreen() && !childViewState.headsUpIsVisible
|
||||||
|
&& !ambientState.isDozingAndNotPulsing(child)
|
||||||
&& childViewState.yTranslation < ambientState.getTopPadding()
|
&& childViewState.yTranslation < ambientState.getTopPadding()
|
||||||
+ ambientState.getStackTranslation()) {
|
+ ambientState.getStackTranslation()) {
|
||||||
if (childrenOnTop != 0.0f) {
|
if (childrenOnTop != 0.0f) {
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ public class StackScrollState {
|
|||||||
viewState.scaleX = view.getScaleX();
|
viewState.scaleX = view.getScaleX();
|
||||||
viewState.scaleY = view.getScaleY();
|
viewState.scaleY = view.getScaleY();
|
||||||
viewState.inShelf = false;
|
viewState.inShelf = false;
|
||||||
|
viewState.headsUpIsVisible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExpandableViewState getViewStateForView(View requestedView) {
|
public ExpandableViewState getViewStateForView(View requestedView) {
|
||||||
|
|||||||
Reference in New Issue
Block a user