Merge changes I3e8594f6,I2c6d40ee into rvc-dev

* changes:
  Made translation of headers consistent when going into the shelf
  Clipping headers to the shelf as well
This commit is contained in:
Selim Cinek
2020-03-04 03:14:29 +00:00
committed by Android (Google) Code Review
11 changed files with 293 additions and 154 deletions

View File

@@ -31,13 +31,16 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginEnd="8dp" android:layout_marginEnd="8dp"
android:gravity="bottom" android:gravity="bottom"
android:orientation="horizontal"> android:orientation="horizontal"
android:forceHasOverlappingRendering="false"
android:clipChildren="false">
<FrameLayout <FrameLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="start|center_vertical" android:gravity="start|center_vertical"
android:layout_weight="1"> android:layout_weight="1"
android:forceHasOverlappingRendering="false">
<TextView <TextView
style="@style/TextAppearance.NotificationSectionHeaderButton" style="@style/TextAppearance.NotificationSectionHeaderButton"
@@ -53,6 +56,7 @@
android:layout_height="48dp" android:layout_height="48dp"
android:padding="8dp" android:padding="8dp"
android:scaleType="fitCenter" android:scaleType="fitCenter"
android:forceHasOverlappingRendering="false"
/> />
<ImageView <ImageView
@@ -60,6 +64,7 @@
android:layout_height="48dp" android:layout_height="48dp"
android:padding="8dp" android:padding="8dp"
android:scaleType="fitCenter" android:scaleType="fitCenter"
android:forceHasOverlappingRendering="false"
/> />
<ImageView <ImageView
@@ -67,6 +72,7 @@
android:layout_height="48dp" android:layout_height="48dp"
android:padding="8dp" android:padding="8dp"
android:scaleType="fitCenter" android:scaleType="fitCenter"
android:forceHasOverlappingRendering="false"
/> />
<ImageView <ImageView
@@ -74,6 +80,7 @@
android:layout_height="48dp" android:layout_height="48dp"
android:padding="8dp" android:padding="8dp"
android:scaleType="fitCenter" android:scaleType="fitCenter"
android:forceHasOverlappingRendering="false"
/> />
<ImageView <ImageView
@@ -81,6 +88,7 @@
android:layout_height="48dp" android:layout_height="48dp"
android:padding="8dp" android:padding="8dp"
android:scaleType="fitCenter" android:scaleType="fitCenter"
android:forceHasOverlappingRendering="false"
/> />
</LinearLayout> </LinearLayout>

View File

@@ -32,6 +32,8 @@
android:layout_gravity="bottom" android:layout_gravity="bottom"
android:gravity="center_vertical" android:gravity="center_vertical"
android:orientation="horizontal" android:orientation="horizontal"
android:forceHasOverlappingRendering="false"
android:clipChildren="false"
> >
<include layout="@layout/status_bar_notification_section_header_contents"/> <include layout="@layout/status_bar_notification_section_header_contents"/>
</LinearLayout> </LinearLayout>

View File

@@ -27,6 +27,7 @@
android:id="@+id/header_label" android:id="@+id/header_label"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:forceHasOverlappingRendering="false"
android:text="@string/notification_section_header_gentle" android:text="@string/notification_section_header_gentle"
/> />
@@ -41,5 +42,6 @@
android:tint="?attr/wallpaperTextColor" android:tint="?attr/wallpaperTextColor"
android:tintMode="src_in" android:tintMode="src_in"
android:visibility="gone" android:visibility="gone"
android:forceHasOverlappingRendering="false"
/> />
</merge> </merge>

View File

@@ -184,8 +184,8 @@
<!-- Vertical translation of pulsing notification animations --> <!-- Vertical translation of pulsing notification animations -->
<dimen name="pulsing_notification_appear_translation">10dp</dimen> <dimen name="pulsing_notification_appear_translation">10dp</dimen>
<!-- The amount the content shifts upwards when transforming into the icon --> <!-- The amount the content shifts upwards when transforming into the shelf -->
<dimen name="notification_icon_transform_content_shift">32dp</dimen> <dimen name="shelf_transform_content_shift">32dp</dimen>
<!-- The padding on the bottom of the notifications on the keyguard --> <!-- The padding on the bottom of the notifications on the keyguard -->
<dimen name="keyguard_indication_bottom_padding">12sp</dimen> <dimen name="keyguard_indication_bottom_padding">12sp</dimen>

View File

@@ -273,47 +273,37 @@ public class NotificationShelf extends ActivatableNotificationView implements
int backgroundTop = 0; int backgroundTop = 0;
int clipTopAmount = 0; int clipTopAmount = 0;
float firstElementRoundness = 0.0f; float firstElementRoundness = 0.0f;
ActivatableNotificationView previousRow = null; ActivatableNotificationView previousAnv = null;
for (int i = 0; i < mHostLayout.getChildCount(); i++) { for (int i = 0; i < mHostLayout.getChildCount(); i++) {
ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i); ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i);
if (!(child instanceof ActivatableNotificationView) if (!child.needsClippingToShelf() || child.getVisibility() == GONE) {
|| child.getVisibility() == GONE || child == this) {
continue; continue;
} }
ActivatableNotificationView row = (ActivatableNotificationView) child;
float notificationClipEnd; float notificationClipEnd;
boolean aboveShelf = ViewState.getFinalTranslationZ(row) > baseZHeight boolean aboveShelf = ViewState.getFinalTranslationZ(child) > baseZHeight
|| row.isPinned(); || child.isPinned();
boolean isLastChild = child == lastChild; boolean isLastChild = child == lastChild;
float rowTranslationY = row.getTranslationY(); float rowTranslationY = child.getTranslationY();
if ((isLastChild && !child.isInShelf()) || aboveShelf || backgroundForceHidden) { if ((isLastChild && !child.isInShelf()) || aboveShelf || backgroundForceHidden) {
notificationClipEnd = shelfStart + getIntrinsicHeight(); notificationClipEnd = shelfStart + getIntrinsicHeight();
} else { } else {
notificationClipEnd = shelfStart - mPaddingBetweenElements; notificationClipEnd = shelfStart - mPaddingBetweenElements;
float height = notificationClipEnd - rowTranslationY;
if (!row.isBelowSpeedBump() && height <= getNotificationMergeSize()) {
// We want the gap to close when we reached the minimum size and only shrink
// before
notificationClipEnd = Math.min(shelfStart,
rowTranslationY + getNotificationMergeSize());
}
} }
int clipTop = updateNotificationClipHeight(row, notificationClipEnd, notGoneIndex); int clipTop = updateNotificationClipHeight(child, notificationClipEnd, notGoneIndex);
clipTopAmount = Math.max(clipTop, clipTopAmount); clipTopAmount = Math.max(clipTop, clipTopAmount);
float inShelfAmount = updateShelfTransformation(child, expandAmount, scrolling,
scrollingFast, expandingAnimated, isLastChild);
// If the current row is an ExpandableNotificationRow, update its color, roundedness, // If the current row is an ExpandableNotificationRow, update its color, roundedness,
// and icon state. // and icon state.
if (row instanceof ExpandableNotificationRow) { if (child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow expandableRow = (ExpandableNotificationRow) row; ExpandableNotificationRow expandableRow = (ExpandableNotificationRow) child;
float inShelfAmount = updateIconAppearance(expandableRow, expandAmount, scrolling,
scrollingFast,
expandingAnimated, isLastChild);
numViewsInShelf += inShelfAmount; numViewsInShelf += inShelfAmount;
int ownColorUntinted = row.getBackgroundColorWithoutTint(); int ownColorUntinted = expandableRow.getBackgroundColorWithoutTint();
if (rowTranslationY >= shelfStart && mNotGoneIndex == -1) { if (rowTranslationY >= shelfStart && mNotGoneIndex == -1) {
mNotGoneIndex = notGoneIndex; mNotGoneIndex = notGoneIndex;
setTintColor(previousColor); setTintColor(previousColor);
@@ -330,10 +320,10 @@ public class NotificationShelf extends ActivatableNotificationView implements
if (colorOfViewBeforeLast == NO_COLOR) { if (colorOfViewBeforeLast == NO_COLOR) {
colorOfViewBeforeLast = ownColorUntinted; colorOfViewBeforeLast = ownColorUntinted;
} }
row.setOverrideTintColor(colorOfViewBeforeLast, inShelfAmount); expandableRow.setOverrideTintColor(colorOfViewBeforeLast, inShelfAmount);
} else { } else {
colorOfViewBeforeLast = ownColorUntinted; colorOfViewBeforeLast = ownColorUntinted;
row.setOverrideTintColor(NO_COLOR, 0 /* overrideAmount */); expandableRow.setOverrideTintColor(NO_COLOR, 0 /* overrideAmount */);
} }
if (notGoneIndex != 0 || !aboveShelf) { if (notGoneIndex != 0 || !aboveShelf) {
expandableRow.setAboveShelf(false); expandableRow.setAboveShelf(false);
@@ -346,8 +336,8 @@ public class NotificationShelf extends ActivatableNotificationView implements
// since they don't show up on AOD // since they don't show up on AOD
if (iconState != null && iconState.clampedAppearAmount == 1.0f) { if (iconState != null && iconState.clampedAppearAmount == 1.0f) {
// only if the first icon is fully in the shelf we want to clip to it! // only if the first icon is fully in the shelf we want to clip to it!
backgroundTop = (int) (row.getTranslationY() - getTranslationY()); backgroundTop = (int) (child.getTranslationY() - getTranslationY());
firstElementRoundness = row.getCurrentTopRoundness(); firstElementRoundness = expandableRow.getCurrentTopRoundness();
} }
} }
@@ -355,25 +345,31 @@ public class NotificationShelf extends ActivatableNotificationView implements
notGoneIndex++; notGoneIndex++;
} }
if (row.isFirstInSection() && previousRow != null && previousRow.isLastInSection()) { if (child instanceof ActivatableNotificationView) {
// If the top of the shelf is between the view before a gap and the view after a gap ActivatableNotificationView anv =
// then we need to adjust the shelf's top roundness. (ActivatableNotificationView) child;
float distanceToGapBottom = row.getTranslationY() - getTranslationY(); if (anv.isFirstInSection() && previousAnv != null
float distanceToGapTop = getTranslationY() && previousAnv.isLastInSection()) {
- (previousRow.getTranslationY() + previousRow.getActualHeight()); // If the top of the shelf is between the view before a gap and the view after a
if (distanceToGapTop > 0) { // gap then we need to adjust the shelf's top roundness.
// We interpolate our top roundness so that it's fully rounded if we're at the float distanceToGapBottom = child.getTranslationY() - getTranslationY();
// bottom of the gap, and not rounded at all if we're at the top of the gap float distanceToGapTop = getTranslationY()
// (directly up against the bottom of previousRow) - (previousAnv.getTranslationY() + previousAnv.getActualHeight());
// Then we apply the same roundness to the bottom of previousRow so that the if (distanceToGapTop > 0) {
// corners join together as the shelf approaches previousRow. // We interpolate our top roundness so that it's fully rounded if we're at
firstElementRoundness = (float) Math.min(1.0, distanceToGapTop / mGapHeight); // the bottom of the gap, and not rounded at all if we're at the top of the
previousRow.setBottomRoundness(firstElementRoundness, // gap (directly up against the bottom of previousAnv)
false /* don't animate */); // Then we apply the same roundness to the bottom of previousAnv so that the
backgroundTop = (int) distanceToGapBottom; // corners join together as the shelf approaches previousAnv.
firstElementRoundness = (float) Math.min(1.0,
distanceToGapTop / mGapHeight);
previousAnv.setBottomRoundness(firstElementRoundness,
false /* don't animate */);
backgroundTop = (int) distanceToGapBottom;
}
} }
previousAnv = anv;
} }
previousRow = row;
} }
clipTransientViews(); clipTransientViews();
@@ -493,27 +489,27 @@ public class NotificationShelf extends ActivatableNotificationView implements
* Update the clipping of this view. * Update the clipping of this view.
* @return the amount that our own top should be clipped * @return the amount that our own top should be clipped
*/ */
private int updateNotificationClipHeight(ActivatableNotificationView row, private int updateNotificationClipHeight(ExpandableView view,
float notificationClipEnd, int childIndex) { float notificationClipEnd, int childIndex) {
float viewEnd = row.getTranslationY() + row.getActualHeight(); float viewEnd = view.getTranslationY() + view.getActualHeight();
boolean isPinned = (row.isPinned() || row.isHeadsUpAnimatingAway()) boolean isPinned = (view.isPinned() || view.isHeadsUpAnimatingAway())
&& !mAmbientState.isDozingAndNotPulsing(row); && !mAmbientState.isDozingAndNotPulsing(view);
boolean shouldClipOwnTop; boolean shouldClipOwnTop;
if (mAmbientState.isPulseExpanding()) { if (mAmbientState.isPulseExpanding()) {
shouldClipOwnTop = childIndex == 0; shouldClipOwnTop = childIndex == 0;
} else { } else {
shouldClipOwnTop = row.showingPulsing(); shouldClipOwnTop = view.showingPulsing();
} }
if (viewEnd > notificationClipEnd && !shouldClipOwnTop if (viewEnd > notificationClipEnd && !shouldClipOwnTop
&& (mAmbientState.isShadeExpanded() || !isPinned)) { && (mAmbientState.isShadeExpanded() || !isPinned)) {
int clipBottomAmount = (int) (viewEnd - notificationClipEnd); int clipBottomAmount = (int) (viewEnd - notificationClipEnd);
if (isPinned) { if (isPinned) {
clipBottomAmount = Math.min(row.getIntrinsicHeight() - row.getCollapsedHeight(), clipBottomAmount = Math.min(view.getIntrinsicHeight() - view.getCollapsedHeight(),
clipBottomAmount); clipBottomAmount);
} }
row.setClipBottomAmount(clipBottomAmount); view.setClipBottomAmount(clipBottomAmount);
} else { } else {
row.setClipBottomAmount(0); view.setClipBottomAmount(0);
} }
if (shouldClipOwnTop) { if (shouldClipOwnTop) {
return (int) (viewEnd - getTranslationY()); return (int) (viewEnd - getTranslationY());
@@ -532,31 +528,28 @@ public class NotificationShelf extends ActivatableNotificationView implements
} }
/** /**
* @return the icon amount how much this notification is in the shelf; * @return the amount how much this notification is in the shelf
*/ */
private float updateIconAppearance(ExpandableNotificationRow row, float expandAmount, private float updateShelfTransformation(ExpandableView view, float expandAmount,
boolean scrolling, boolean scrollingFast, boolean expandingAnimated, boolean scrolling, boolean scrollingFast, boolean expandingAnimated,
boolean isLastChild) { boolean isLastChild) {
StatusBarIconView icon = row.getEntry().expandedIcon; StatusBarIconView icon = view.getShelfIcon();
NotificationIconContainer.IconState iconState = getIconState(icon); NotificationIconContainer.IconState iconState = getIconState(icon);
if (iconState == null) {
return 0.0f;
}
// Let calculate how much the view is in the shelf // Let calculate how much the view is in the shelf
float viewStart = row.getTranslationY(); float viewStart = view.getTranslationY();
int fullHeight = row.getActualHeight() + mPaddingBetweenElements; int fullHeight = view.getActualHeight() + mPaddingBetweenElements;
float iconTransformDistance = getIntrinsicHeight() * 1.5f; float iconTransformDistance = getIntrinsicHeight() * 1.5f;
iconTransformDistance *= NotificationUtils.interpolate(1.f, 1.5f, expandAmount); iconTransformDistance *= NotificationUtils.interpolate(1.f, 1.5f, expandAmount);
iconTransformDistance = Math.min(iconTransformDistance, fullHeight); iconTransformDistance = Math.min(iconTransformDistance, fullHeight);
if (isLastChild) { if (isLastChild) {
fullHeight = Math.min(fullHeight, row.getMinHeight() - getIntrinsicHeight()); fullHeight = Math.min(fullHeight, view.getMinHeight() - getIntrinsicHeight());
iconTransformDistance = Math.min(iconTransformDistance, row.getMinHeight() iconTransformDistance = Math.min(iconTransformDistance, view.getMinHeight()
- getIntrinsicHeight()); - getIntrinsicHeight());
} }
float viewEnd = viewStart + fullHeight; float viewEnd = viewStart + fullHeight;
// TODO: fix this check for anchor scrolling. // TODO: fix this check for anchor scrolling.
if (expandingAnimated && mAmbientState.getScrollY() == 0 if (iconState != null && expandingAnimated && mAmbientState.getScrollY() == 0
&& !mAmbientState.isOnKeyguard() && !iconState.isLastExpandIcon) { && !mAmbientState.isOnKeyguard() && !iconState.isLastExpandIcon) {
// We are expanding animated. Because we switch to a linear interpolation in this case, // We are expanding animated. Because we switch to a linear interpolation in this case,
// the last icon may be stuck in between the shelf position and the notification // the last icon may be stuck in between the shelf position and the notification
@@ -566,10 +559,10 @@ public class NotificationShelf extends ActivatableNotificationView implements
// We need to persist this, since after the expansion, the behavior should still be the // We need to persist this, since after the expansion, the behavior should still be the
// same. // same.
float position = mAmbientState.getIntrinsicPadding() float position = mAmbientState.getIntrinsicPadding()
+ mHostLayout.getPositionInLinearLayout(row); + mHostLayout.getPositionInLinearLayout(view);
int maxShelfStart = mMaxLayoutHeight - getIntrinsicHeight(); int maxShelfStart = mMaxLayoutHeight - getIntrinsicHeight();
if (position < maxShelfStart && position + row.getIntrinsicHeight() >= maxShelfStart if (position < maxShelfStart && position + view.getIntrinsicHeight() >= maxShelfStart
&& row.getTranslationY() < position) { && view.getTranslationY() < position) {
iconState.isLastExpandIcon = true; iconState.isLastExpandIcon = true;
iconState.customTransformHeight = NO_VALUE; iconState.customTransformHeight = NO_VALUE;
// Let's check if we're close enough to snap into the shelf // Let's check if we're close enough to snap into the shelf
@@ -584,16 +577,16 @@ public class NotificationShelf extends ActivatableNotificationView implements
} }
} }
float fullTransitionAmount; float fullTransitionAmount;
float iconTransitionAmount; float transitionAmount;
float shelfStart = getTranslationY(); float shelfStart = getTranslationY();
if (iconState.hasCustomTransformHeight()) { if (iconState != null && iconState.hasCustomTransformHeight()) {
fullHeight = iconState.customTransformHeight; fullHeight = iconState.customTransformHeight;
iconTransformDistance = iconState.customTransformHeight; iconTransformDistance = iconState.customTransformHeight;
} }
boolean fullyInOrOut = true; boolean fullyInOrOut = true;
if (viewEnd >= shelfStart && (!mAmbientState.isUnlockHintRunning() || row.isInShelf()) if (viewEnd >= shelfStart && (!mAmbientState.isUnlockHintRunning() || view.isInShelf())
&& (mAmbientState.isShadeExpanded() && (mAmbientState.isShadeExpanded()
|| (!row.isPinned() && !row.isHeadsUpAnimatingAway()))) { || (!view.isPinned() && !view.isHeadsUpAnimatingAway()))) {
if (viewStart < shelfStart) { if (viewStart < shelfStart) {
float fullAmount = (shelfStart - viewStart) / fullHeight; float fullAmount = (shelfStart - viewStart) / fullHeight;
fullAmount = Math.min(1.0f, fullAmount); fullAmount = Math.min(1.0f, fullAmount);
@@ -603,88 +596,98 @@ public class NotificationShelf extends ActivatableNotificationView implements
interpolatedAmount, fullAmount, expandAmount); interpolatedAmount, fullAmount, expandAmount);
fullTransitionAmount = 1.0f - interpolatedAmount; fullTransitionAmount = 1.0f - interpolatedAmount;
iconTransitionAmount = (shelfStart - viewStart) / iconTransformDistance; transitionAmount = (shelfStart - viewStart) / iconTransformDistance;
iconTransitionAmount = Math.min(1.0f, iconTransitionAmount); transitionAmount = Math.min(1.0f, transitionAmount);
iconTransitionAmount = 1.0f - iconTransitionAmount; transitionAmount = 1.0f - transitionAmount;
fullyInOrOut = false; fullyInOrOut = false;
} else { } else {
fullTransitionAmount = 1.0f; fullTransitionAmount = 1.0f;
iconTransitionAmount = 1.0f; transitionAmount = 1.0f;
} }
} else { } else {
fullTransitionAmount = 0.0f; fullTransitionAmount = 0.0f;
iconTransitionAmount = 0.0f; transitionAmount = 0.0f;
} }
if (fullyInOrOut && !expandingAnimated && iconState.isLastExpandIcon) { if (iconState != null && fullyInOrOut && !expandingAnimated && iconState.isLastExpandIcon) {
iconState.isLastExpandIcon = false; iconState.isLastExpandIcon = false;
iconState.customTransformHeight = NO_VALUE; iconState.customTransformHeight = NO_VALUE;
} }
updateIconPositioning(row, iconTransitionAmount, fullTransitionAmount, updateIconPositioning(view, transitionAmount, fullTransitionAmount,
iconTransformDistance, scrolling, scrollingFast, expandingAnimated, isLastChild); iconTransformDistance, scrolling, scrollingFast, expandingAnimated, isLastChild);
return fullTransitionAmount; return fullTransitionAmount;
} }
private void updateIconPositioning(ExpandableNotificationRow row, float iconTransitionAmount, private void updateIconPositioning(ExpandableView view, float iconTransitionAmount,
float fullTransitionAmount, float iconTransformDistance, boolean scrolling, float fullTransitionAmount, float iconTransformDistance, boolean scrolling,
boolean scrollingFast, boolean expandingAnimated, boolean isLastChild) { boolean scrollingFast, boolean expandingAnimated, boolean isLastChild) {
StatusBarIconView icon = row.getEntry().expandedIcon; StatusBarIconView icon = view.getShelfIcon();
NotificationIconContainer.IconState iconState = getIconState(icon); NotificationIconContainer.IconState iconState = getIconState(icon);
float contentTransformationAmount;
if (iconState == null) { if (iconState == null) {
return; contentTransformationAmount = iconTransitionAmount;
}
boolean forceInShelf = iconState.isLastExpandIcon && !iconState.hasCustomTransformHeight();
float clampedAmount = iconTransitionAmount > 0.5f ? 1.0f : 0.0f;
if (clampedAmount == fullTransitionAmount) {
iconState.noAnimations = (scrollingFast || expandingAnimated) && !forceInShelf;
iconState.useFullTransitionAmount = iconState.noAnimations
|| (!ICON_ANMATIONS_WHILE_SCROLLING && fullTransitionAmount == 0.0f && scrolling);
iconState.useLinearTransitionAmount = !ICON_ANMATIONS_WHILE_SCROLLING
&& fullTransitionAmount == 0.0f && !mAmbientState.isExpansionChanging();
iconState.translateContent = mMaxLayoutHeight - getTranslationY()
- getIntrinsicHeight() > 0;
}
if (!forceInShelf && (scrollingFast || (expandingAnimated
&& iconState.useFullTransitionAmount && !ViewState.isAnimatingY(icon)))) {
iconState.cancelAnimations(icon);
iconState.useFullTransitionAmount = true;
iconState.noAnimations = true;
}
if (iconState.hasCustomTransformHeight()) {
iconState.useFullTransitionAmount = true;
}
if (iconState.isLastExpandIcon) {
iconState.translateContent = false;
}
float transitionAmount;
if (mAmbientState.isHiddenAtAll() && !row.isInShelf()) {
transitionAmount = mAmbientState.isFullyHidden() ? 1 : 0;
} else if (isLastChild || !USE_ANIMATIONS_WHEN_OPENING || iconState.useFullTransitionAmount
|| iconState.useLinearTransitionAmount) {
transitionAmount = iconTransitionAmount;
} else { } else {
// We take the clamped position instead boolean forceInShelf =
transitionAmount = clampedAmount; iconState.isLastExpandIcon && !iconState.hasCustomTransformHeight();
iconState.needsCannedAnimation = iconState.clampedAppearAmount != clampedAmount float clampedAmount = iconTransitionAmount > 0.5f ? 1.0f : 0.0f;
&& !mNoAnimationsInThisFrame; if (clampedAmount == fullTransitionAmount) {
} iconState.noAnimations = (scrollingFast || expandingAnimated) && !forceInShelf;
iconState.iconAppearAmount = !USE_ANIMATIONS_WHEN_OPENING iconState.useFullTransitionAmount = iconState.noAnimations
|| (!ICON_ANMATIONS_WHILE_SCROLLING && fullTransitionAmount == 0.0f
&& scrolling);
iconState.useLinearTransitionAmount = !ICON_ANMATIONS_WHILE_SCROLLING
&& fullTransitionAmount == 0.0f && !mAmbientState.isExpansionChanging();
iconState.translateContent = mMaxLayoutHeight - getTranslationY()
- getIntrinsicHeight() > 0;
}
if (!forceInShelf && (scrollingFast || (expandingAnimated
&& iconState.useFullTransitionAmount && !ViewState.isAnimatingY(icon)))) {
iconState.cancelAnimations(icon);
iconState.useFullTransitionAmount = true;
iconState.noAnimations = true;
}
if (iconState.hasCustomTransformHeight()) {
iconState.useFullTransitionAmount = true;
}
if (iconState.isLastExpandIcon) {
iconState.translateContent = false;
}
float transitionAmount;
if (mAmbientState.isHiddenAtAll() && !view.isInShelf()) {
transitionAmount = mAmbientState.isFullyHidden() ? 1 : 0;
} else if (isLastChild || !USE_ANIMATIONS_WHEN_OPENING
|| iconState.useFullTransitionAmount || iconState.useFullTransitionAmount
? fullTransitionAmount || iconState.useLinearTransitionAmount) {
: transitionAmount; transitionAmount = iconTransitionAmount;
iconState.clampedAppearAmount = clampedAmount; } else {
float contentTransformationAmount = !row.isAboveShelf() && !row.showingPulsing() // We take the clamped position instead
transitionAmount = clampedAmount;
iconState.needsCannedAnimation = iconState.clampedAppearAmount != clampedAmount
&& !mNoAnimationsInThisFrame;
}
iconState.iconAppearAmount = !USE_ANIMATIONS_WHEN_OPENING
|| iconState.useFullTransitionAmount
? fullTransitionAmount
: transitionAmount;
iconState.clampedAppearAmount = clampedAmount;
contentTransformationAmount = !view.isAboveShelf() && !view.showingPulsing()
&& (isLastChild || iconState.translateContent) && (isLastChild || iconState.translateContent)
? iconTransitionAmount ? iconTransitionAmount
: 0.0f; : 0.0f;
row.setContentTransformationAmount(contentTransformationAmount, isLastChild); setIconTransformationAmount(view, transitionAmount, iconTransformDistance,
setIconTransformationAmount(row, transitionAmount, iconTransformDistance, clampedAmount != transitionAmount, isLastChild);
clampedAmount != transitionAmount, isLastChild); }
view.setContentTransformationAmount(contentTransformationAmount, isLastChild);
} }
private void setIconTransformationAmount(ExpandableNotificationRow row, private void setIconTransformationAmount(ExpandableView view,
float transitionAmount, float iconTransformDistance, boolean usingLinearInterpolation, float transitionAmount, float iconTransformDistance, boolean usingLinearInterpolation,
boolean isLastChild) { boolean isLastChild) {
StatusBarIconView icon = row.getEntry().expandedIcon; if (!(view instanceof ExpandableNotificationRow)) {
return;
}
ExpandableNotificationRow row = (ExpandableNotificationRow) view;
StatusBarIconView icon = row.getShelfIcon();
NotificationIconContainer.IconState iconState = getIconState(icon); NotificationIconContainer.IconState iconState = getIconState(icon);
View rowIcon = row.getNotificationIcon(); View rowIcon = row.getNotificationIcon();
@@ -950,6 +953,11 @@ public class NotificationShelf extends ActivatableNotificationView implements
updateRelativeOffset(); updateRelativeOffset();
} }
@Override
public boolean needsClippingToShelf() {
return false;
}
public void onUiModeChanged() { public void onUiModeChanged() {
updateBackgroundColors(); updateBackgroundColors();
} }

View File

@@ -968,14 +968,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
return mCurrentBackgroundTint; return mCurrentBackgroundTint;
} }
public boolean isPinned() {
return false;
}
public boolean isHeadsUpAnimatingAway() {
return false;
}
public boolean isHeadsUp() { public boolean isHeadsUp() {
return false; return false;
} }

View File

@@ -142,7 +142,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private LayoutListener mLayoutListener; private LayoutListener mLayoutListener;
private RowContentBindStage mRowContentBindStage; private RowContentBindStage mRowContentBindStage;
private int mIconTransformContentShift; private int mIconTransformContentShift;
private int mIconTransformContentShiftNoIcon;
private int mMaxHeadsUpHeightBeforeN; private int mMaxHeadsUpHeightBeforeN;
private int mMaxHeadsUpHeightBeforeP; private int mMaxHeadsUpHeightBeforeP;
private int mMaxHeadsUpHeight; private int mMaxHeadsUpHeight;
@@ -312,10 +311,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private boolean mHeadsupDisappearRunning; private boolean mHeadsupDisappearRunning;
private View mChildAfterViewWhenDismissed; private View mChildAfterViewWhenDismissed;
private View mGroupParentWhenDismissed; private View mGroupParentWhenDismissed;
private float mContentTransformationAmount;
private boolean mIconsVisible = true; private boolean mIconsVisible = true;
private boolean mAboveShelf; private boolean mAboveShelf;
private boolean mIsLastChild;
private Runnable mOnDismissRunnable; private Runnable mOnDismissRunnable;
private boolean mIsLowPriority; private boolean mIsLowPriority;
private boolean mIsColorized; private boolean mIsColorized;
@@ -1504,18 +1501,19 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
updateIconVisibilities(); updateIconVisibilities();
} }
private void updateContentTransformation() { @Override
protected void updateContentTransformation() {
if (mExpandAnimationRunning) { if (mExpandAnimationRunning) {
return; return;
} }
float contentAlpha; super.updateContentTransformation();
float translationY = -mContentTransformationAmount * mIconTransformContentShift; }
if (mIsLastChild) {
contentAlpha = 1.0f - mContentTransformationAmount; @Override
contentAlpha = Math.min(contentAlpha / 0.5f, 1.0f); protected void applyContentTransformation(float contentAlpha, float translationY) {
contentAlpha = Interpolators.ALPHA_OUT.getInterpolation(contentAlpha); super.applyContentTransformation(contentAlpha, translationY);
translationY *= 0.4f; if (!mIsLastChild) {
} else { // Don't fade views unless we're last
contentAlpha = 1.0f; contentAlpha = 1.0f;
} }
for (NotificationContentView l : mLayouts) { for (NotificationContentView l : mLayouts) {
@@ -1672,8 +1670,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
Resources res = getResources(); Resources res = getResources();
mIncreasedPaddingBetweenElements = res.getDimensionPixelSize( mIncreasedPaddingBetweenElements = res.getDimensionPixelSize(
R.dimen.notification_divider_height_increased); R.dimen.notification_divider_height_increased);
mIconTransformContentShiftNoIcon = res.getDimensionPixelSize(
R.dimen.notification_icon_transform_content_shift);
mEnableNonGroupedNotificationExpand = mEnableNonGroupedNotificationExpand =
res.getBoolean(R.bool.config_enableNonGroupedNotificationExpand); res.getBoolean(R.bool.config_enableNonGroupedNotificationExpand);
mShowGroupBackgroundWhenExpanded = mShowGroupBackgroundWhenExpanded =
@@ -2136,6 +2132,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
return mChildIsExpanding; return mChildIsExpanding;
} }
@Override
public StatusBarIconView getShelfIcon() {
return getEntry().expandedIcon;
}
@Override @Override
protected boolean shouldClipToActualHeight() { protected boolean shouldClipToActualHeight() {
return super.shouldClipToActualHeight() && !mExpandAnimationRunning; return super.shouldClipToActualHeight() && !mExpandAnimationRunning;
@@ -2472,10 +2473,15 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
CachingIconView icon = notificationHeader.getIcon(); CachingIconView icon = notificationHeader.getIcon();
mIconTransformContentShift = getRelativeTopPadding(icon) + icon.getHeight(); mIconTransformContentShift = getRelativeTopPadding(icon) + icon.getHeight();
} else { } else {
mIconTransformContentShift = mIconTransformContentShiftNoIcon; mIconTransformContentShift = mContentShift;
} }
} }
@Override
protected float getContentTransformationShift() {
return mIconTransformContentShift;
}
@Override @Override
public void notifyHeightChanged(boolean needsAnimation) { public void notifyHeightChanged(boolean needsAnimation) {
super.notifyHeightChanged(needsAnimation); super.notifyHeightChanged(needsAnimation);

View File

@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.row;
import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorListenerAdapter;
import android.content.Context; import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Paint; import android.graphics.Paint;
import android.graphics.Rect; import android.graphics.Rect;
import android.util.AttributeSet; import android.util.AttributeSet;
@@ -28,6 +29,9 @@ import android.widget.FrameLayout;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.android.systemui.Dumpable; import com.android.systemui.Dumpable;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.stack.ExpandableViewState; import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
@@ -58,11 +62,26 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable {
private ViewGroup mTransientContainer; private ViewGroup mTransientContainer;
private boolean mInShelf; private boolean mInShelf;
private boolean mTransformingInShelf; private boolean mTransformingInShelf;
protected float mContentTransformationAmount;
protected boolean mIsLastChild;
protected int mContentShift;
private final ExpandableViewState mViewState; private final ExpandableViewState mViewState;
public ExpandableView(Context context, AttributeSet attrs) { public ExpandableView(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
mViewState = createExpandableViewState(); mViewState = createExpandableViewState();
initDimens();
}
private void initDimens() {
mContentShift = getResources().getDimensionPixelSize(
R.dimen.shelf_transform_content_shift);
}
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
initDimens();
} }
@Override @Override
@@ -139,6 +158,22 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable {
localY < (bottom + slop); localY < (bottom + slop);
} }
/**
* @return if this view needs to be clipped to the shelf
*/
public boolean needsClippingToShelf() {
return true;
}
public boolean isPinned() {
return false;
}
public boolean isHeadsUpAnimatingAway() {
return false;
}
/** /**
* Sets the actual height of this notification. This is different than the laid out * Sets the actual height of this notification. This is different than the laid out
* {@link View#getHeight()}, as we want to avoid layouting during scrolling and expanding. * {@link View#getHeight()}, as we want to avoid layouting during scrolling and expanding.
@@ -578,7 +613,7 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable {
/** /**
* @return whether the current view doesn't add height to the overall content. This means that * @return whether the current view doesn't add height to the overall content. This means that
* if it is added to a list of items, it's content will still have the same height. * if it is added to a list of items, its content will still have the same height.
* An example is the notification shelf, that is always placed on top of another view. * An example is the notification shelf, that is always placed on top of another view.
*/ */
public boolean hasNoContentHeight() { public boolean hasNoContentHeight() {
@@ -596,6 +631,59 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable {
return mInShelf; return mInShelf;
} }
public @Nullable StatusBarIconView getShelfIcon() {
return null;
}
/**
* Set how much this notification is transformed into the shelf.
*
* @param contentTransformationAmount A value from 0 to 1 indicating how much we are transformed
* to the content away
* @param isLastChild is this the last child in the list. If true, then the transformation is
* different since its content fades out.
*/
public void setContentTransformationAmount(float contentTransformationAmount,
boolean isLastChild) {
boolean changeTransformation = isLastChild != mIsLastChild;
changeTransformation |= mContentTransformationAmount != contentTransformationAmount;
mIsLastChild = isLastChild;
mContentTransformationAmount = contentTransformationAmount;
if (changeTransformation) {
updateContentTransformation();
}
}
/**
* Update the content representation based on the amount we are transformed into the shelf.
*/
protected void updateContentTransformation() {
float translationY = -mContentTransformationAmount * getContentTransformationShift();
float contentAlpha = 1.0f - mContentTransformationAmount;
contentAlpha = Math.min(contentAlpha / 0.5f, 1.0f);
contentAlpha = Interpolators.ALPHA_OUT.getInterpolation(contentAlpha);
if (mIsLastChild) {
translationY *= 0.4f;
}
applyContentTransformation(contentAlpha, translationY);
}
/**
* @return how much the content shifts up when going into the shelf
*/
protected float getContentTransformationShift() {
return mContentShift;
}
/**
* Apply the contentTransformation when going into the shelf.
*
* @param contentAlpha The alpha that should be applied
* @param translationY the translationY that should be applied
*/
protected void applyContentTransformation(float contentAlpha, float translationY) {
}
/** /**
* @param transformingInShelf whether the view is currently transforming into the shelf in an * @param transformingInShelf whether the view is currently transforming into the shelf in an
* animated way * animated way

View File

@@ -49,6 +49,7 @@ public abstract class StackScrollerDecorView extends ExpandableView {
public StackScrollerDecorView(Context context, AttributeSet attrs) { public StackScrollerDecorView(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
setClipChildren(false);
} }
@Override @Override
@@ -205,6 +206,11 @@ public abstract class StackScrollerDecorView extends ExpandableView {
setContentVisible(true); setContentVisible(true);
} }
@Override
public boolean needsClippingToShelf() {
return false;
}
@Override @Override
public boolean hasOverlappingRendering() { public boolean hasOverlappingRendering() {
return false; return false;

View File

@@ -76,6 +76,19 @@ class PeopleHubView(context: Context, attrs: AttributeSet) :
} }
} }
override fun needsClippingToShelf(): Boolean {
return true
}
override fun applyContentTransformation(contentAlpha: Float, translationY: Float) {
super.applyContentTransformation(contentAlpha, translationY)
for (i in 0 until contents.childCount) {
val view = contents.getChildAt(i)
view.alpha = contentAlpha
view.translationY = translationY
}
}
private inner class PersonDataListenerImpl(val avatarView: ImageView) : private inner class PersonDataListenerImpl(val avatarView: ImageView) :
DataListener<PersonViewModel?> { DataListener<PersonViewModel?> {

View File

@@ -108,12 +108,26 @@ public class SectionHeaderView extends StackScrollerDecorView {
mLabelView.setOnClickListener(listener); mLabelView.setOnClickListener(listener);
} }
@Override
protected void applyContentTransformation(float contentAlpha, float translationY) {
super.applyContentTransformation(contentAlpha, translationY);
mLabelView.setAlpha(contentAlpha);
mLabelView.setTranslationY(translationY);
mClearAllButton.setAlpha(contentAlpha);
mClearAllButton.setTranslationY(translationY);
}
/** Fired when the user clicks on the "X" button on the far right of the header. */ /** Fired when the user clicks on the "X" button on the far right of the header. */
void setOnClearAllClickListener(View.OnClickListener listener) { void setOnClearAllClickListener(View.OnClickListener listener) {
mOnClearClickListener = listener; mOnClearClickListener = listener;
mClearAllButton.setOnClickListener(listener); mClearAllButton.setOnClickListener(listener);
} }
@Override
public boolean needsClippingToShelf() {
return true;
}
void setHeaderText(@StringRes int resId) { void setHeaderText(@StringRes int resId) {
mLabelView.setText(resId); mLabelView.setText(resId);
} }