summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Selim Cinek <cinek@google.com> 2020-03-31 20:02:01 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2020-03-31 20:02:01 +0000
commit9bad85af2b646fa3c6dcacf85f5f02b901e8cc29 (patch)
tree4321ad67cb0eda0ff483a26662ed0fc5973a956e
parentb259d151ce0fbd8f075d557e1d2d1c95d910d74b (diff)
parente027da23c040f393aa9d5089afa33a9b0dcd0449 (diff)
Merge changes I0d79642d,If8756ac8,I29e73897,Ia8c5121a,I533b8f06 into rvc-dev
* changes: Indented the conversation action list Fixed some issues where conversation badges would not be visible Improved the animations of the conversation badges Important conversations now also transform into the shelf Adapted Shelf algorithm to also use conversation icons
-rw-r--r--core/java/android/app/Notification.java2
-rw-r--r--core/java/android/view/NotificationHeaderView.java8
-rw-r--r--core/java/com/android/internal/widget/CachingIconView.java49
-rw-r--r--core/java/com/android/internal/widget/ConversationLayout.java105
-rw-r--r--core/java/com/android/internal/widget/MessagingPropertyAnimator.java2
-rw-r--r--core/res/res/layout/notification_template_material_conversation.xml9
-rw-r--r--core/res/res/values/symbols.xml2
-rw-r--r--packages/SystemUI/src/com/android/systemui/Interpolators.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java303
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java94
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java59
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt30
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationProperties.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java49
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java2
26 files changed, 656 insertions, 260 deletions
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index e137acf4dc70..9b42fa2012e1 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5817,7 +5817,7 @@ public class Notification implements Parcelable
PorterDuff.Mode.SRC_ATOP);
}
- contentView.setInt(R.id.notification_header, "setOriginalIconColor",
+ contentView.setInt(R.id.icon, "setOriginalIconColor",
colorable ? color : NotificationHeaderView.NO_COLOR);
}
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index 18e0132e2c4e..0359f3b4fde7 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -65,7 +65,6 @@ public class NotificationHeaderView extends ViewGroup {
private View mMicIcon;
private View mAppOps;
private View mAudiblyAlertedIcon;
- private int mIconColor;
private boolean mExpanded;
private boolean mShowExpandButtonAtEnd;
private boolean mShowWorkBadgeAtEnd;
@@ -315,13 +314,8 @@ public class NotificationHeaderView extends ViewGroup {
updateTouchListener();
}
- @RemotableViewMethod
- public void setOriginalIconColor(int color) {
- mIconColor = color;
- }
-
public int getOriginalIconColor() {
- return mIconColor;
+ return mIcon.getOriginalIconColor();
}
public int getOriginalNotificationColor() {
diff --git a/core/java/com/android/internal/widget/CachingIconView.java b/core/java/com/android/internal/widget/CachingIconView.java
index bd0623e1144e..84cde1b84e14 100644
--- a/core/java/com/android/internal/widget/CachingIconView.java
+++ b/core/java/com/android/internal/widget/CachingIconView.java
@@ -46,6 +46,9 @@ public class CachingIconView extends ImageView {
private boolean mForceHidden;
private int mDesiredVisibility;
private Consumer<Integer> mOnVisibilityChangedListener;
+ private Consumer<Boolean> mOnForceHiddenChangedListener;
+ private int mIconColor;
+ private boolean mWillBeForceHidden;
@UnsupportedAppUsage
public CachingIconView(Context context, @Nullable AttributeSet attrs) {
@@ -184,10 +187,18 @@ public class CachingIconView extends ImageView {
/**
* Set the icon to be forcibly hidden, even when it's visibility is changed to visible.
+ * This is necessary since we still want to keep certain views hidden when their visibility
+ * is modified from other sources like the shelf.
*/
public void setForceHidden(boolean forceHidden) {
- mForceHidden = forceHidden;
- updateVisibility();
+ if (forceHidden != mForceHidden) {
+ mForceHidden = forceHidden;
+ mWillBeForceHidden = false;
+ updateVisibility();
+ if (mOnForceHiddenChangedListener != null) {
+ mOnForceHiddenChangedListener.accept(forceHidden);
+ }
+ }
}
@Override
@@ -209,4 +220,38 @@ public class CachingIconView extends ImageView {
public void setOnVisibilityChangedListener(Consumer<Integer> listener) {
mOnVisibilityChangedListener = listener;
}
+
+ public void setOnForceHiddenChangedListener(Consumer<Boolean> listener) {
+ mOnForceHiddenChangedListener = listener;
+ }
+
+
+ public boolean isForceHidden() {
+ return mForceHidden;
+ }
+
+ @RemotableViewMethod
+ public void setOriginalIconColor(int color) {
+ mIconColor = color;
+ }
+
+ public int getOriginalIconColor() {
+ return mIconColor;
+ }
+
+ /**
+ * @return if the view will be forceHidden after an animation
+ */
+ public boolean willBeForceHidden() {
+ return mWillBeForceHidden;
+ }
+
+ /**
+ * Set that this view will be force hidden after an animation
+ *
+ * @param forceHidden if it will be forcehidden
+ */
+ public void setWillBeForceHidden(boolean forceHidden) {
+ mWillBeForceHidden = forceHidden;
+ }
}
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index bedf55d52391..1336ec412cdb 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -18,6 +18,8 @@ package com.android.internal.widget;
import static com.android.internal.widget.MessagingGroup.IMAGE_DISPLAY_LOCATION_EXTERNAL;
import static com.android.internal.widget.MessagingGroup.IMAGE_DISPLAY_LOCATION_INLINE;
+import static com.android.internal.widget.MessagingPropertyAnimator.ALPHA_IN;
+import static com.android.internal.widget.MessagingPropertyAnimator.ALPHA_OUT;
import android.annotation.AttrRes;
import android.annotation.NonNull;
@@ -106,7 +108,7 @@ public class ConversationLayout extends FrameLayout
private CharSequence mNameReplacement;
private boolean mIsCollapsed;
private ImageResolver mImageResolver;
- private ImageView mConversationIcon;
+ private CachingIconView mConversationIcon;
private View mConversationIconContainer;
private int mConversationIconTopPadding;
private int mConversationIconTopPaddingExpandedGroup;
@@ -114,7 +116,7 @@ public class ConversationLayout extends FrameLayout
private int mExpandedGroupMessagePaddingNoAppName;
private TextView mConversationText;
private View mConversationIconBadge;
- private ImageView mConversationIconBadgeBg;
+ private CachingIconView mConversationIconBadgeBg;
private Icon mLargeIcon;
private View mExpandButtonContainer;
private ViewGroup mExpandButtonAndContentContainer;
@@ -125,7 +127,7 @@ public class ConversationLayout extends FrameLayout
private int mConversationAvatarSize;
private int mConversationAvatarSizeExpanded;
private CachingIconView mIcon;
- private View mImportanceRingView;
+ private CachingIconView mImportanceRingView;
private int mExpandedGroupSideMargin;
private int mExpandedGroupSideMarginFacePile;
private View mConversationFacePile;
@@ -140,11 +142,15 @@ public class ConversationLayout extends FrameLayout
private int mContentMarginEnd;
private Rect mMessagingClipRect;
private ObservableTextView mAppName;
+ private ViewGroup mActions;
+ private int mConversationContentStart;
+ private int mInternalButtonPadding;
private boolean mAppNameGone;
private int mFacePileAvatarSize;
private int mFacePileAvatarSizeExpandedGroup;
private int mFacePileProtectionWidth;
private int mFacePileProtectionWidthExpanded;
+ private boolean mImportantConversation;
public ConversationLayout(@NonNull Context context) {
super(context);
@@ -168,6 +174,7 @@ public class ConversationLayout extends FrameLayout
protected void onFinishInflate() {
super.onFinishInflate();
mMessagingLinearLayout = findViewById(R.id.notification_messaging);
+ mActions = findViewById(R.id.actions);
mMessagingLinearLayout.setMessagingLayout(this);
mImageMessageContainer = findViewById(R.id.conversation_image_message_container);
// We still want to clip, but only on the top, since views can temporarily out of bounds
@@ -186,9 +193,41 @@ public class ConversationLayout extends FrameLayout
mConversationIconBadge = findViewById(R.id.conversation_icon_badge);
mConversationIconBadgeBg = findViewById(R.id.conversation_icon_badge_bg);
mIcon.setOnVisibilityChangedListener((visibility) -> {
- // Always keep the badge visibility in sync with the icon. This is necessary in cases
- // Where the icon is being hidden externally like in group children.
- mConversationIconBadge.setVisibility(visibility);
+
+ // Let's hide the background directly or in an animated way
+ boolean isGone = visibility == GONE;
+ int oldVisibility = mConversationIconBadgeBg.getVisibility();
+ boolean wasGone = oldVisibility == GONE;
+ if (wasGone != isGone) {
+ // Keep the badge gone state in sync with the icon. This is necessary in cases
+ // Where the icon is being hidden externally like in group children.
+ mConversationIconBadgeBg.animate().cancel();
+ mConversationIconBadgeBg.setVisibility(visibility);
+ }
+
+ // Let's handle the importance ring which can also be be gone normally
+ oldVisibility = mImportanceRingView.getVisibility();
+ wasGone = oldVisibility == GONE;
+ visibility = !mImportantConversation ? GONE : visibility;
+ isGone = visibility == GONE;
+ if (wasGone != isGone) {
+ // Keep the badge visibility in sync with the icon. This is necessary in cases
+ // Where the icon is being hidden externally like in group children.
+ mImportanceRingView.animate().cancel();
+ mImportanceRingView.setVisibility(visibility);
+ }
+ });
+ // When the small icon is gone, hide the rest of the badge
+ mIcon.setOnForceHiddenChangedListener((forceHidden) -> {
+ animateViewForceHidden(mConversationIconBadgeBg, forceHidden);
+ animateViewForceHidden(mImportanceRingView, forceHidden);
+ });
+
+ // When the conversation icon is gone, hide the whole badge
+ mConversationIcon.setOnForceHiddenChangedListener((forceHidden) -> {
+ animateViewForceHidden(mConversationIconBadgeBg, forceHidden);
+ animateViewForceHidden(mImportanceRingView, forceHidden);
+ animateViewForceHidden(mIcon, forceHidden);
});
mConversationText = findViewById(R.id.conversation_text);
mExpandButtonContainer = findViewById(R.id.expand_button_container);
@@ -238,6 +277,33 @@ public class ConversationLayout extends FrameLayout
mAppName.setOnVisibilityChangedListener((visibility) -> {
onAppNameVisibilityChanged();
});
+ mConversationContentStart = getResources().getDimensionPixelSize(
+ R.dimen.conversation_content_start);
+ mInternalButtonPadding
+ = getResources().getDimensionPixelSize(R.dimen.button_padding_horizontal_material)
+ + getResources().getDimensionPixelSize(R.dimen.button_inset_horizontal_material);
+ }
+
+ private void animateViewForceHidden(CachingIconView view, boolean forceHidden) {
+ boolean nowForceHidden = view.willBeForceHidden() || view.isForceHidden();
+ if (forceHidden == nowForceHidden) {
+ // We are either already forceHidden or will be
+ return;
+ }
+ view.animate().cancel();
+ view.setWillBeForceHidden(forceHidden);
+ view.animate()
+ .scaleX(forceHidden ? 0.5f : 1.0f)
+ .scaleY(forceHidden ? 0.5f : 1.0f)
+ .alpha(forceHidden ? 0.0f : 1.0f)
+ .setInterpolator(forceHidden ? ALPHA_OUT : ALPHA_IN)
+ .setDuration(160);
+ if (view.getVisibility() != VISIBLE) {
+ view.setForceHidden(forceHidden);
+ } else {
+ view.animate().withEndAction(() -> view.setForceHidden(forceHidden));
+ }
+ view.animate().start();
}
@RemotableViewMethod
@@ -255,9 +321,14 @@ public class ConversationLayout extends FrameLayout
*/
@RemotableViewMethod
public void setIsImportantConversation(boolean isImportantConversation) {
+ mImportantConversation = isImportantConversation;
mImportanceRingView.setVisibility(isImportantConversation ? VISIBLE : GONE);
}
+ public boolean isImportantConversation() {
+ return mImportantConversation;
+ }
+
/**
* Set this layout to show the collapsed representation.
*
@@ -363,7 +434,6 @@ public class ConversationLayout extends FrameLayout
private void updateConversationLayout() {
// Set avatar and name
CharSequence conversationText = mConversationTitle;
- // TODO: display the secondary text somewhere
if (mIsOneToOne) {
// Let's resolve the icon / text from the last sender
mConversationIcon.setVisibility(VISIBLE);
@@ -418,6 +488,27 @@ public class ConversationLayout extends FrameLayout
updateIconPositionAndSize();
updateImageMessages();
updatePaddingsBasedOnContentAvailability();
+ updateActionListPadding();
+ }
+
+ private void updateActionListPadding() {
+ if (mActions == null) {
+ return;
+ }
+ View firstAction = mActions.getChildAt(0);
+ if (firstAction != null) {
+ // Let's visually position the first action where the content starts
+ int paddingStart = mConversationContentStart;
+
+ MarginLayoutParams layoutParams = (MarginLayoutParams) firstAction.getLayoutParams();
+ paddingStart -= layoutParams.getMarginStart();
+ paddingStart -= mInternalButtonPadding;
+
+ mActions.setPaddingRelative(paddingStart,
+ mActions.getPaddingTop(),
+ mActions.getPaddingEnd(),
+ mActions.getPaddingBottom());
+ }
}
private void updateImageMessages() {
diff --git a/core/java/com/android/internal/widget/MessagingPropertyAnimator.java b/core/java/com/android/internal/widget/MessagingPropertyAnimator.java
index 7703cb0f13db..a3a75c098a00 100644
--- a/core/java/com/android/internal/widget/MessagingPropertyAnimator.java
+++ b/core/java/com/android/internal/widget/MessagingPropertyAnimator.java
@@ -32,7 +32,7 @@ import com.android.internal.R;
*/
public class MessagingPropertyAnimator implements View.OnLayoutChangeListener {
private static final long APPEAR_ANIMATION_LENGTH = 210;
- private static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
+ public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f);
private static final int TAG_TOP_ANIMATOR = R.id.tag_top_animator;
private static final int TAG_TOP = R.id.tag_top_override;
diff --git a/core/res/res/layout/notification_template_material_conversation.xml b/core/res/res/layout/notification_template_material_conversation.xml
index 7cadecbbdb91..46d3d1326920 100644
--- a/core/res/res/layout/notification_template_material_conversation.xml
+++ b/core/res/res/layout/notification_template_material_conversation.xml
@@ -42,7 +42,7 @@
>
<!-- Big icon: 52x52, 12dp padding left + top, 16dp padding right -->
- <ImageView
+ <com.android.internal.widget.CachingIconView
android:id="@+id/conversation_icon"
android:layout_width="@dimen/conversation_avatar_size"
android:layout_height="@dimen/conversation_avatar_size"
@@ -64,11 +64,12 @@
android:layout_marginLeft="@dimen/conversation_badge_side_margin"
android:layout_marginTop="@dimen/conversation_badge_side_margin"
>
- <ImageView
+ <com.android.internal.widget.CachingIconView
android:id="@+id/conversation_icon_badge_bg"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/conversation_badge_background"
+ android:forceHasOverlappingRendering="false"
/>
<com.android.internal.widget.CachingIconView
android:id="@+id/icon"
@@ -76,13 +77,15 @@
android:layout_height="match_parent"
android:layout_margin="4dp"
android:layout_gravity="center"
+ android:forceHasOverlappingRendering="false"
/>
- <ImageView
+ <com.android.internal.widget.CachingIconView
android:id="@+id/conversation_icon_badge_ring"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/conversation_badge_ring"
android:visibility="gone"
+ android:forceHasOverlappingRendering="false"
/>
</FrameLayout>
</FrameLayout>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 04c6a41833df..0fea372ea580 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3895,6 +3895,8 @@
<java-symbol type="dimen" name="conversation_icon_container_top_padding_small_avatar" />
<java-symbol type="dimen" name="conversation_icon_container_top_padding_no_app_name" />
<java-symbol type="layout" name="notification_template_material_conversation" />
+ <java-symbol type="dimen" name="button_padding_horizontal_material" />
+ <java-symbol type="dimen" name="button_inset_horizontal_material" />
<java-symbol type="layout" name="conversation_face_pile_layout" />
<!-- Intent resolver and share sheet -->
diff --git a/packages/SystemUI/src/com/android/systemui/Interpolators.java b/packages/SystemUI/src/com/android/systemui/Interpolators.java
index 2b3ea3ab56c0..6923079dd5c4 100644
--- a/packages/SystemUI/src/com/android/systemui/Interpolators.java
+++ b/packages/SystemUI/src/com/android/systemui/Interpolators.java
@@ -49,6 +49,8 @@ public class Interpolators {
public static final Interpolator CUSTOM_40_40 = new PathInterpolator(0.4f, 0f, 0.6f, 1f);
public static final Interpolator HEADS_UP_APPEAR = new HeadsUpAppearInterpolator();
public static final Interpolator ICON_OVERSHOT = new PathInterpolator(0.4f, 0f, 0.2f, 1.4f);
+ public static final Interpolator ICON_OVERSHOT_LESS
+ = new PathInterpolator(0.4f, 0f, 0.2f, 1.1f);
public static final Interpolator PANEL_CLOSE_ACCELERATED
= new PathInterpolator(0.3f, 0, 0.5f, 1);
public static final Interpolator BOUNCE = new BounceInterpolator();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 651623b45f6a..d798692879f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -27,6 +27,7 @@ import android.graphics.Rect;
import android.os.SystemProperties;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.MathUtils;
import android.view.DisplayCutout;
import android.view.View;
import android.view.ViewGroup;
@@ -536,55 +537,39 @@ public class NotificationShelf extends ActivatableNotificationView implements
// Let calculate how much the view is in the shelf
float viewStart = view.getTranslationY();
int fullHeight = view.getActualHeight() + mPaddingBetweenElements;
- float iconTransformDistance = getIntrinsicHeight() * 1.5f;
- iconTransformDistance *= NotificationUtils.interpolate(1.f, 1.5f, expandAmount);
- iconTransformDistance = Math.min(iconTransformDistance, fullHeight);
+ float iconTransformStart = calculateIconTransformationStart(view);
+
+ float transformDistance = getIntrinsicHeight() * 1.5f;
+ transformDistance *= NotificationUtils.interpolate(1.f, 1.5f, expandAmount);
+ transformDistance = Math.min(transformDistance, fullHeight);
+
+ // Let's make sure the transform distance is
+ // at most to the icon (relevant for conversations)
+ transformDistance = Math.min(viewStart + fullHeight - iconTransformStart,
+ transformDistance);
+
if (isLastChild) {
fullHeight = Math.min(fullHeight, view.getMinHeight() - getIntrinsicHeight());
- iconTransformDistance = Math.min(iconTransformDistance, view.getMinHeight()
+ transformDistance = Math.min(transformDistance, view.getMinHeight()
- getIntrinsicHeight());
}
float viewEnd = viewStart + fullHeight;
- // TODO: fix this check for anchor scrolling.
- if (iconState != null && expandingAnimated && mAmbientState.getScrollY() == 0
- && !mAmbientState.isOnKeyguard() && !iconState.isLastExpandIcon) {
- // 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
- // position, which looks pretty bad. We therefore optimize this case by applying a
- // shorter transition such that the icon is either fully in the notification or we clamp
- // it into the shelf if it's close enough.
- // We need to persist this, since after the expansion, the behavior should still be the
- // same.
- float position = mAmbientState.getIntrinsicPadding()
- + mHostLayout.getPositionInLinearLayout(view);
- int maxShelfStart = mMaxLayoutHeight - getIntrinsicHeight();
- if (position < maxShelfStart && position + view.getIntrinsicHeight() >= maxShelfStart
- && view.getTranslationY() < position) {
- iconState.isLastExpandIcon = true;
- iconState.customTransformHeight = NO_VALUE;
- // Let's check if we're close enough to snap into the shelf
- boolean forceInShelf = mMaxLayoutHeight - getIntrinsicHeight() - position
- < getIntrinsicHeight();
- if (!forceInShelf) {
- // We are overlapping the shelf but not enough, so the icon needs to be
- // repositioned
- iconState.customTransformHeight = (int) (mMaxLayoutHeight
- - getIntrinsicHeight() - position);
- }
- }
- }
+ handleCustomTransformHeight(view, expandingAnimated, iconState);
+
float fullTransitionAmount;
float transitionAmount;
+ float contentTransformationAmount;
float shelfStart = getTranslationY();
- if (iconState != null && iconState.hasCustomTransformHeight()) {
- fullHeight = iconState.customTransformHeight;
- iconTransformDistance = iconState.customTransformHeight;
- }
boolean fullyInOrOut = true;
if (viewEnd >= shelfStart && (!mAmbientState.isUnlockHintRunning() || view.isInShelf())
&& (mAmbientState.isShadeExpanded()
|| (!view.isPinned() && !view.isHeadsUpAnimatingAway()))) {
if (viewStart < shelfStart) {
+ if (iconState != null && iconState.hasCustomTransformHeight()) {
+ fullHeight = iconState.customTransformHeight;
+ transformDistance = iconState.customTransformHeight;
+ }
+
float fullAmount = (shelfStart - viewStart) / fullHeight;
fullAmount = Math.min(1.0f, fullAmount);
float interpolatedAmount = Interpolators.ACCELERATE_DECELERATE.getInterpolation(
@@ -593,87 +578,163 @@ public class NotificationShelf extends ActivatableNotificationView implements
interpolatedAmount, fullAmount, expandAmount);
fullTransitionAmount = 1.0f - interpolatedAmount;
- transitionAmount = (shelfStart - viewStart) / iconTransformDistance;
- transitionAmount = Math.min(1.0f, transitionAmount);
+ if (isLastChild) {
+ // If it's the last child we should use all of the notification to transform
+ // instead of just to the icon, since that can be quite low.
+ transitionAmount = (shelfStart - viewStart) / transformDistance;
+ } else {
+ transitionAmount = (shelfStart - iconTransformStart) / transformDistance;
+ }
+ transitionAmount = MathUtils.constrain(transitionAmount, 0.0f, 1.0f);
transitionAmount = 1.0f - transitionAmount;
fullyInOrOut = false;
} else {
fullTransitionAmount = 1.0f;
transitionAmount = 1.0f;
}
+
+ // Transforming the content
+ contentTransformationAmount = (shelfStart - viewStart) / transformDistance;
+ contentTransformationAmount = Math.min(1.0f, contentTransformationAmount);
+ contentTransformationAmount = 1.0f - contentTransformationAmount;
} else {
fullTransitionAmount = 0.0f;
transitionAmount = 0.0f;
+ contentTransformationAmount = 0.0f;
}
if (iconState != null && fullyInOrOut && !expandingAnimated && iconState.isLastExpandIcon) {
iconState.isLastExpandIcon = false;
iconState.customTransformHeight = NO_VALUE;
}
+
+ // Update the content transformation amount
+ if (view.isAboveShelf() || view.showingPulsing()
+ || (!isLastChild && iconState != null && !iconState.translateContent)) {
+ contentTransformationAmount = 0.0f;
+ }
+ view.setContentTransformationAmount(contentTransformationAmount, isLastChild);
+
+ // Update the positioning of the icon
updateIconPositioning(view, transitionAmount, fullTransitionAmount,
- iconTransformDistance, scrolling, scrollingFast, expandingAnimated, isLastChild);
+ transformDistance, scrolling, scrollingFast, expandingAnimated, isLastChild);
+
return fullTransitionAmount;
}
+ /**
+ * @return the location where the transformation into the shelf should start.
+ */
+ private float calculateIconTransformationStart(ExpandableView view) {
+ View target = view.getShelfTransformationTarget();
+ if (target == null) {
+ return view.getTranslationY();
+ }
+ float start = view.getTranslationY() + view.getRelativeTopPadding(target);
+
+ // Let's not start the transformation right at the icon but by the padding before it.
+ start -= view.getShelfIcon().getTop();
+ return start;
+ }
+
+ private void handleCustomTransformHeight(ExpandableView view, boolean expandingAnimated,
+ NotificationIconContainer.IconState iconState) {
+ if (iconState != null && expandingAnimated && mAmbientState.getScrollY() == 0
+ && !mAmbientState.isOnKeyguard() && !iconState.isLastExpandIcon) {
+ // 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
+ // position, which looks pretty bad. We therefore optimize this case by applying a
+ // shorter transition such that the icon is either fully in the notification or we clamp
+ // it into the shelf if it's close enough.
+ // We need to persist this, since after the expansion, the behavior should still be the
+ // same.
+ float position = mAmbientState.getIntrinsicPadding()
+ + mHostLayout.getPositionInLinearLayout(view);
+ int maxShelfStart = mMaxLayoutHeight - getIntrinsicHeight();
+ if (position < maxShelfStart && position + view.getIntrinsicHeight() >= maxShelfStart
+ && view.getTranslationY() < position) {
+ iconState.isLastExpandIcon = true;
+ iconState.customTransformHeight = NO_VALUE;
+ // Let's check if we're close enough to snap into the shelf
+ boolean forceInShelf = mMaxLayoutHeight - getIntrinsicHeight() - position
+ < getIntrinsicHeight();
+ if (!forceInShelf) {
+ // We are overlapping the shelf but not enough, so the icon needs to be
+ // repositioned
+ iconState.customTransformHeight = (int) (mMaxLayoutHeight
+ - getIntrinsicHeight() - position);
+ }
+ }
+ }
+ }
+
private void updateIconPositioning(ExpandableView view, float iconTransitionAmount,
float fullTransitionAmount, float iconTransformDistance, boolean scrolling,
boolean scrollingFast, boolean expandingAnimated, boolean isLastChild) {
StatusBarIconView icon = view.getShelfIcon();
NotificationIconContainer.IconState iconState = getIconState(icon);
- float contentTransformationAmount;
if (iconState == null) {
- contentTransformationAmount = iconTransitionAmount;
+ return;
+ }
+ boolean forceInShelf =
+ iconState.isLastExpandIcon && !iconState.hasCustomTransformHeight();
+ boolean clampInShelf = iconTransitionAmount > 0.5f || isTargetClipped(view);
+ float clampedAmount = clampInShelf ? 1.0f : 0.0f;
+ if (iconTransitionAmount == clampedAmount) {
+ iconState.noAnimations = (scrollingFast || expandingAnimated) && !forceInShelf;
+ iconState.useFullTransitionAmount = iconState.noAnimations
+ || (!ICON_ANMATIONS_WHILE_SCROLLING && iconTransitionAmount == 0.0f
+ && scrolling);
+ iconState.useLinearTransitionAmount = !ICON_ANMATIONS_WHILE_SCROLLING
+ && iconTransitionAmount == 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.useLinearTransitionAmount) {
+ transitionAmount = iconTransitionAmount;
} else {
- 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() && !view.isInShelf()) {
- transitionAmount = mAmbientState.isFullyHidden() ? 1 : 0;
- } else if (isLastChild || !USE_ANIMATIONS_WHEN_OPENING
- || iconState.useFullTransitionAmount
- || iconState.useLinearTransitionAmount) {
- transitionAmount = iconTransitionAmount;
- } else {
- // 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)
- ? iconTransitionAmount
- : 0.0f;
- setIconTransformationAmount(view, transitionAmount, iconTransformDistance,
- clampedAmount != transitionAmount, isLastChild);
+ // We take the clamped position instead
+ transitionAmount = clampedAmount;
+ iconState.needsCannedAnimation = iconState.clampedAppearAmount != clampedAmount
+ && !mNoAnimationsInThisFrame;
}
- view.setContentTransformationAmount(contentTransformationAmount, isLastChild);
+ iconState.iconAppearAmount = !USE_ANIMATIONS_WHEN_OPENING
+ || iconState.useFullTransitionAmount
+ ? fullTransitionAmount
+ : transitionAmount;
+ iconState.clampedAppearAmount = clampedAmount;
+ setIconTransformationAmount(view, transitionAmount, iconTransformDistance,
+ clampedAmount != transitionAmount, isLastChild);
+ }
+
+ private boolean isTargetClipped(ExpandableView view) {
+ View target = view.getShelfTransformationTarget();
+ if (target == null) {
+ return false;
+ }
+ // We should never clip the target, let's instead put it into the shelf!
+ float endOfTarget = view.getTranslationY()
+ + view.getContentTranslation()
+ + view.getRelativeTopPadding(target)
+ + target.getHeight();
+
+ return endOfTarget >= getTranslationY() - mPaddingBetweenElements;
}
private void setIconTransformationAmount(ExpandableView view,
@@ -686,40 +747,63 @@ public class NotificationShelf extends ActivatableNotificationView implements
StatusBarIconView icon = row.getShelfIcon();
NotificationIconContainer.IconState iconState = getIconState(icon);
+ View rowIcon = row.getShelfTransformationTarget();
- View rowIcon = row.getNotificationIcon();
- float notificationIconPosition = row.getTranslationY() + row.getContentTranslation();
- boolean stayingInShelf = row.isInShelf() && !row.isTransformingIntoShelf();
- if (usingLinearInterpolation && !stayingInShelf) {
- // If we interpolate from the notification position, this might lead to a slightly
- // odd interpolation, since the notification position changes as well. Let's interpolate
- // from a fixed distance. We can only do this if we don't animate and the icon is
- // always in the interpolated positon.
- notificationIconPosition = getTranslationY() - iconTransformDistance;
- }
+ // Let's resolve the relative positions of the icons
float notificationIconSize = 0.0f;
int iconTopPadding;
+ int iconStartPadding;
if (rowIcon != null) {
iconTopPadding = row.getRelativeTopPadding(rowIcon);
+ iconStartPadding = row.getRelativeStartPadding(rowIcon);
notificationIconSize = rowIcon.getHeight();
} else {
iconTopPadding = mIconAppearTopPadding;
+ iconStartPadding = 0;
}
- notificationIconPosition += iconTopPadding;
- float shelfIconPosition = getTranslationY() + icon.getTop();
- float iconSize = mAmbientState.isFullyHidden() ? mHiddenShelfIconSize : mIconSize;
- shelfIconPosition += (icon.getHeight() - icon.getIconScale() * iconSize) / 2.0f;
+
+ float shelfIconSize = mAmbientState.isFullyHidden() ? mHiddenShelfIconSize : mIconSize;
+ shelfIconSize = shelfIconSize * icon.getIconScale();
+
+ // Get the icon correctly positioned in Y
+ float notificationIconPositionY = row.getTranslationY() + row.getContentTranslation();
+ float targetYPosition = 0;
+ boolean stayingInShelf = row.isInShelf() && !row.isTransformingIntoShelf();
+ if (usingLinearInterpolation && !stayingInShelf) {
+ // If we interpolate from the notification position, this might lead to a slightly
+ // odd interpolation, since the notification position changes as well.
+ // Let's instead interpolate directly to the top left of the notification
+ targetYPosition = NotificationUtils.interpolate(
+ Math.min(notificationIconPositionY + mIconAppearTopPadding
+ - getTranslationY(), 0),
+ 0,
+ transitionAmount);
+ }
+ notificationIconPositionY += iconTopPadding;
+ float shelfIconPositionY = getTranslationY() + icon.getTop();
+ shelfIconPositionY += (icon.getHeight() - shelfIconSize) / 2.0f;
float iconYTranslation = NotificationUtils.interpolate(
- notificationIconPosition - shelfIconPosition,
- 0,
+ notificationIconPositionY - shelfIconPositionY,
+ targetYPosition,
transitionAmount);
- float shelfIconSize = iconSize * icon.getIconScale();
+
+ // Get the icon correctly positioned in X
+ // Even in RTL it's the left, since we're inverting the location in post
+ float shelfIconPositionX = icon.getLeft();
+ shelfIconPositionX += (1.0f - icon.getIconScale()) * icon.getWidth() / 2.0f;
+ float iconXTranslation = NotificationUtils.interpolate(
+ iconStartPadding - shelfIconPositionX,
+ mShelfIcons.getActualPaddingStart(),
+ transitionAmount);
+
+ // Let's handle the case that there's no Icon
float alpha = 1.0f;
boolean noIcon = !row.isShowingIcon();
if (noIcon) {
// The view currently doesn't have an icon, lets transform it in!
alpha = transitionAmount;
notificationIconSize = shelfIconSize / 2.0f;
+ iconXTranslation = mShelfIcons.getActualPaddingStart();
}
// The notification size is different from the size in the shelf / statusbar
float newSize = NotificationUtils.interpolate(notificationIconSize, shelfIconSize,
@@ -735,6 +819,7 @@ public class NotificationShelf extends ActivatableNotificationView implements
}
iconState.alpha = alpha;
iconState.yTranslation = iconYTranslation;
+ iconState.xTranslation = iconXTranslation;
if (stayingInShelf) {
iconState.iconAppearAmount = 1.0f;
iconState.alpha = 1.0f;
@@ -751,7 +836,7 @@ public class NotificationShelf extends ActivatableNotificationView implements
int backgroundColor = getBackgroundColorWithoutTint();
int shelfColor = icon.getContrastedStaticDrawableColor(backgroundColor);
if (!noIcon && shelfColor != StatusBarIconView.NO_COLOR) {
- int iconColor = row.getVisibleNotificationHeader().getOriginalIconColor();
+ int iconColor = row.getOriginalIconColor();
shelfColor = NotificationUtils.interpolateColors(iconColor, shelfColor,
iconState.iconAppearAmount);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 12add8c8d9cc..8cf8a2299922 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -159,7 +159,7 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi
private boolean mDismissed;
private Runnable mOnDismissListener;
private boolean mIncreasedSize;
- private boolean mTintIcons = true;
+ private boolean mShowsConversation;
public StatusBarIconView(Context context, String slot, StatusBarNotification sbn) {
this(context, slot, sbn, false);
@@ -613,7 +613,7 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi
}
private void updateIconColor() {
- if (!mTintIcons) {
+ if (mShowsConversation) {
setColorFilter(null);
return;
}
@@ -913,7 +913,11 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi
}
private void updatePivot() {
- setPivotX((1 - mIconScale) / 2.0f * getWidth());
+ if (isLayoutRtl()) {
+ setPivotX((1 + mIconScale) / 2.0f * getWidth());
+ } else {
+ setPivotX((1 - mIconScale) / 2.0f * getWidth());
+ }
setPivotY((getHeight() - mIconScale * getWidth()) / 2.0f);
}
@@ -960,18 +964,26 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi
}
/**
- * Sets whether the icon should be tinted. If the state differs from the supplied setting, this
+ * Sets whether this icon shows a person and should be tinted.
+ * If the state differs from the supplied setting, this
* will update the icon colors.
*
- * @param shouldTint Whether the icon should be tinted.
+ * @param showsConversation Whether the icon shows a person
*/
- public void setTintIcons(boolean shouldTint) {
- if (mTintIcons != shouldTint) {
- mTintIcons = shouldTint;
+ public void setShowsConversation(boolean showsConversation) {
+ if (mShowsConversation != showsConversation) {
+ mShowsConversation = showsConversation;
updateIconColor();
}
}
+ /**
+ * @return if this icon shows a conversation
+ */
+ public boolean showsConversation() {
+ return mShowsConversation;
+ }
+
public interface OnVisibilityChangedListener {
void onVisibilityChanged(int newVisibility);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java
index fe565529db32..1f9d3af70b4f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java
@@ -96,7 +96,7 @@ public class PropertyAnimator {
|| previousAnimator.getAnimatedFraction() == 0)) {
animator.setStartDelay(properties.delay);
}
- AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
+ AnimatorListenerAdapter listener = properties.getAnimationFinishListener(property);
if (listener != null) {
animator.addListener(listener);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
index bb0fcafdb354..da8ad2da5c87 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
@@ -100,7 +100,7 @@ class IconManager @Inject constructor(
// TODO: This doesn't belong here
shelfIcon.setOnVisibilityChangedListener { newVisibility: Int ->
if (entry.row != null) {
- entry.row.setIconsVisible(newVisibility != View.VISIBLE)
+ entry.row.setShelfIconVisible(newVisibility == View.VISIBLE)
}
}
@@ -258,7 +258,7 @@ class IconManager @Inject constructor(
iconDescriptor: StatusBarIcon,
iconView: StatusBarIconView
) {
- iconView.setTintIcons(shouldTintIconView(entry, iconView))
+ iconView.setShowsConversation(showsConversation(entry, iconView, iconDescriptor))
if (!iconView.set(iconDescriptor)) {
throw InflationException("Couldn't create icon $iconDescriptor")
}
@@ -312,15 +312,22 @@ class IconManager @Inject constructor(
}
/**
- * Determines if this icon should be tinted based on the sensitivity of the icon, its context
- * and the user's indicated sensitivity preference.
+ * Determines if this icon shows a conversation based on the sensitivity of the icon, its
+ * context and the user's indicated sensitivity preference. If we're using a fall back icon
+ * of the small icon, we don't consider this to be showing a conversation
*
- * @param iconView The icon that should/should not be tinted.
+ * @param iconView The icon that shows the conversation.
*/
- private fun shouldTintIconView(entry: NotificationEntry, iconView: StatusBarIconView): Boolean {
+ private fun showsConversation(
+ entry: NotificationEntry,
+ iconView: StatusBarIconView,
+ iconDescriptor: StatusBarIcon
+ ): Boolean {
val usedInSensitiveContext =
iconView === entry.icons.shelfIcon || iconView === entry.icons.aodIcon
- return !isImportantConversation(entry) || usedInSensitiveContext && entry.isSensitive
+ val isSmallIcon = iconDescriptor.icon.equals(entry.sbn.notification.smallIcon)
+ return isImportantConversation(entry) && !isSmallIcon
+ && (!usedInSensitiveContext || !entry.isSensitive)
}
private fun isImportantConversation(entry: NotificationEntry): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 0ff058b31527..7deabf79a6dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -31,6 +31,7 @@ import android.animation.ObjectAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.Notification;
import android.app.NotificationChannel;
import android.content.Context;
import android.content.pm.PackageInfo;
@@ -311,7 +312,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private boolean mHeadsupDisappearRunning;
private View mChildAfterViewWhenDismissed;
private View mGroupParentWhenDismissed;
- private boolean mIconsVisible = true;
+ private boolean mShelfIconVisible;
private boolean mAboveShelf;
private Runnable mOnDismissRunnable;
private boolean mIsLowPriority;
@@ -587,17 +588,24 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
ContrastColorUtil.getInstance(mContext));
int color = StatusBarIconView.NO_COLOR;
if (colorize) {
- NotificationHeaderView header = getVisibleNotificationHeader();
- if (header != null) {
- color = header.getOriginalIconColor();
- } else {
- color = mEntry.getContrastedColor(mContext, mIsLowPriority && !isExpanded(),
- getBackgroundColorWithoutTint());
- }
+ color = getOriginalIconColor();
}
expandedIcon.setStaticDrawableColor(color);
}
+ public int getOriginalIconColor() {
+ if (mIsSummaryWithChildren && !shouldShowPublic()) {
+ return mChildrenContainer.getVisibleHeader().getOriginalIconColor();
+ }
+ int color = getShowingLayout().getOriginalIconColor();
+ if (color != Notification.COLOR_INVALID) {
+ return color;
+ } else {
+ return mEntry.getContrastedColor(mContext, mIsLowPriority && !isExpanded(),
+ getBackgroundColorWithoutTint());
+ }
+ }
+
public void setAboveShelfChangedListener(AboveShelfChangedListener aboveShelfChangedListener) {
mAboveShelfChangedListener = aboveShelfChangedListener;
}
@@ -1452,12 +1460,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mOnDismissRunnable = onDismissRunnable;
}
- public View getNotificationIcon() {
- NotificationHeaderView notificationHeader = getVisibleNotificationHeader();
- if (notificationHeader != null) {
- return notificationHeader.getIcon();
+ @Override
+ public View getShelfTransformationTarget() {
+ if (mIsSummaryWithChildren && !shouldShowPublic()) {
+ return mChildrenContainer.getVisibleHeader().getIcon();
}
- return null;
+ return getShowingLayout().getShelfTransformationTarget();
}
/**
@@ -1467,34 +1475,15 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
if (areGutsExposed()) {
return false;
}
- return getVisibleNotificationHeader() != null;
- }
-
- /**
- * Set how much this notification is transformed into an icon.
- *
- * @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 it's content fades out.
- */
- public void setContentTransformationAmount(float contentTransformationAmount,
- boolean isLastChild) {
- boolean changeTransformation = isLastChild != mIsLastChild;
- changeTransformation |= mContentTransformationAmount != contentTransformationAmount;
- mIsLastChild = isLastChild;
- mContentTransformationAmount = contentTransformationAmount;
- if (changeTransformation) {
- updateContentTransformation();
- }
+ return getShelfTransformationTarget() != null;
}
/**
* Set the icons to be visible of this notification.
*/
- public void setIconsVisible(boolean iconsVisible) {
- if (iconsVisible != mIconsVisible) {
- mIconsVisible = iconsVisible;
+ public void setShelfIconVisible(boolean iconVisible) {
+ if (iconVisible != mShelfIconVisible) {
+ mShelfIconVisible = iconVisible;
updateIconVisibilities();
}
}
@@ -1531,37 +1520,14 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
private void updateIconVisibilities() {
- boolean visible = isChildInGroup() || mIconsVisible;
+ // The shelficon is never hidden for children in groups
+ boolean visible = !isChildInGroup() && mShelfIconVisible;
for (NotificationContentView l : mLayouts) {
- l.setIconsVisible(visible);
+ l.setShelfIconVisible(visible);
}
if (mChildrenContainer != null) {
- mChildrenContainer.setIconsVisible(visible);
- }
- }
-
- /**
- * Get the relative top padding of a view relative to this view. This recursively walks up the
- * hierarchy and does the corresponding measuring.
- *
- * @param view the view to the the padding for. The requested view has to be a child of this
- * notification.
- * @return the toppadding
- */
- public int getRelativeTopPadding(View view) {
- int topPadding = 0;
- while (view.getParent() instanceof ViewGroup) {
- topPadding += view.getTop();
- view = (View) view.getParent();
- if (view instanceof ExpandableNotificationRow) {
- return topPadding;
- }
+ mChildrenContainer.setShelfIconVisible(visible);
}
- return topPadding;
- }
-
- public float getContentTranslation() {
- return mPrivateLayout.getTranslationY();
}
public void setIsLowPriority(boolean isLowPriority) {
@@ -2134,7 +2100,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
@Override
- public StatusBarIconView getShelfIcon() {
+ public @NonNull StatusBarIconView getShelfIcon() {
return getEntry().getIcons().getShelfIcon();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index a9f72ff9ea62..ee3b753ab926 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -66,6 +66,7 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable {
protected boolean mIsLastChild;
protected int mContentShift;
private final ExpandableViewState mViewState;
+ private float mContentTranslation;
public ExpandableView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -636,6 +637,56 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable {
}
/**
+ * @return get the transformation target of the shelf, which usually is the icon
+ */
+ public View getShelfTransformationTarget() {
+ return null;
+ }
+
+ /**
+ * Get the relative top padding of a view relative to this view. This recursively walks up the
+ * hierarchy and does the corresponding measuring.
+ *
+ * @param view the view to get the padding for. The requested view has to be a child of this
+ * notification.
+ * @return the toppadding
+ */
+ public int getRelativeTopPadding(View view) {
+ int topPadding = 0;
+ while (view.getParent() instanceof ViewGroup) {
+ topPadding += view.getTop();
+ view = (View) view.getParent();
+ if (view == this) {
+ return topPadding;
+ }
+ }
+ return topPadding;
+ }
+
+
+ /**
+ * Get the relative start padding of a view relative to this view. This recursively walks up the
+ * hierarchy and does the corresponding measuring.
+ *
+ * @param view the view to get the padding for. The requested view has to be a child of this
+ * notification.
+ * @return the start padding
+ */
+ public int getRelativeStartPadding(View view) {
+ boolean isRtl = isLayoutRtl();
+ int startPadding = 0;
+ while (view.getParent() instanceof ViewGroup) {
+ View parent = (View) view.getParent();
+ startPadding += isRtl ? parent.getWidth() - view.getRight() : view.getLeft();
+ view = parent;
+ if (view == this) {
+ return startPadding;
+ }
+ }
+ return startPadding;
+ }
+
+ /**
* Set how much this notification is transformed into the shelf.
*
* @param contentTransformationAmount A value from 0 to 1 indicating how much we are transformed
@@ -665,6 +716,7 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable {
if (mIsLastChild) {
translationY *= 0.4f;
}
+ mContentTranslation = translationY;
applyContentTransformation(contentAlpha, translationY);
}
@@ -709,6 +761,13 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable {
}
/**
+ * return the amount that the content is translated
+ */
+ public float getContentTranslation() {
+ return mContentTranslation;
+ }
+
+ /**
* A listener notifying when {@link #getActualHeight} changes.
*/
public interface OnHeightChangedListener {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 8b8a9012cbdc..9b9225e0bde0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -159,7 +159,7 @@ public class NotificationContentView extends FrameLayout {
private int mContentHeightAtAnimationStart = UNDEFINED;
private boolean mFocusOnVisibilityChange;
private boolean mHeadsUpAnimatingAway;
- private boolean mIconsVisible;
+ private boolean mShelfIconVisible;
private int mClipBottomAmount;
private boolean mIsLowPriority;
private boolean mIsContentExpandable;
@@ -1582,29 +1582,20 @@ public class NotificationContentView extends FrameLayout {
mFocusOnVisibilityChange = true;
}
- public void setIconsVisible(boolean iconsVisible) {
- mIconsVisible = iconsVisible;
+ public void setShelfIconVisible(boolean iconsVisible) {
+ mShelfIconVisible = iconsVisible;
updateIconVisibilities();
}
private void updateIconVisibilities() {
if (mContractedWrapper != null) {
- NotificationHeaderView header = mContractedWrapper.getNotificationHeader();
- if (header != null) {
- header.getIcon().setForceHidden(!mIconsVisible);
- }
+ mContractedWrapper.setShelfIconVisible(mShelfIconVisible);
}
if (mHeadsUpWrapper != null) {
- NotificationHeaderView header = mHeadsUpWrapper.getNotificationHeader();
- if (header != null) {
- header.getIcon().setForceHidden(!mIconsVisible);
- }
+ mHeadsUpWrapper.setShelfIconVisible(mShelfIconVisible);
}
if (mExpandedWrapper != null) {
- NotificationHeaderView header = mExpandedWrapper.getNotificationHeader();
- if (header != null) {
- header.getIcon().setForceHidden(!mIconsVisible);
- }
+ mExpandedWrapper.setShelfIconVisible(mShelfIconVisible);
}
}
@@ -1835,4 +1826,23 @@ public class NotificationContentView extends FrameLayout {
public RemoteInputView getExpandedRemoteInput() {
return mExpandedRemoteInput;
}
+
+ /**
+ * @return get the transformation target of the shelf, which usually is the icon
+ */
+ public View getShelfTransformationTarget() {
+ NotificationViewWrapper visibleWrapper = getVisibleWrapper(mVisibleType);
+ if (visibleWrapper != null) {
+ return visibleWrapper.getShelfTransformationTarget();
+ }
+ return null;
+ }
+
+ public int getOriginalIconColor() {
+ NotificationViewWrapper visibleWrapper = getVisibleWrapper(mVisibleType);
+ if (visibleWrapper != null) {
+ return visibleWrapper.getOriginalIconColor();
+ }
+ return Notification.COLOR_INVALID;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
index 593de23c58de..13e7fe5cd6d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
@@ -18,7 +18,9 @@ package com.android.systemui.statusbar.notification.row.wrapper
import android.content.Context
import android.view.View
+import android.view.View.GONE
import android.view.ViewGroup
+import com.android.internal.widget.CachingIconView
import com.android.internal.widget.ConversationLayout
import com.android.internal.widget.MessagingLinearLayout
import com.android.systemui.R
@@ -44,7 +46,7 @@ class NotificationConversationTemplateViewWrapper constructor(
)
private val conversationLayout: ConversationLayout = view as ConversationLayout
- private lateinit var conversationIcon: View
+ private lateinit var conversationIcon: CachingIconView
private lateinit var conversationBadgeBg: View
private lateinit var expandButton: View
private lateinit var expandButtonContainer: View
@@ -132,6 +134,32 @@ class NotificationConversationTemplateViewWrapper constructor(
)
}
+ override fun setShelfIconVisible(visible: Boolean) {
+ if (conversationLayout.isImportantConversation) {
+ if (conversationIcon.visibility != GONE) {
+ conversationIcon.setForceHidden(visible);
+ // We don't want the small icon to be hidden by the extended wrapper, as force
+ // hiding the conversationIcon will already do that via its listener.
+ return;
+ }
+ }
+ super.setShelfIconVisible(visible)
+ }
+
+ override fun getShelfTransformationTarget(): View? {
+ if (conversationLayout.isImportantConversation) {
+ if (conversationIcon.visibility != GONE) {
+ return conversationIcon
+ } else {
+ // A notification with a fallback icon was set to important. Currently
+ // the transformation doesn't work for these and needs to be fixed. In the meantime
+ // those are using the icon.
+ return super.getShelfTransformationTarget();
+ }
+ }
+ return super.getShelfTransformationTarget()
+ }
+
override fun setRemoteInputVisible(visible: Boolean) =
conversationLayout.showHistoricMessages(visible)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
index a44ad3d7f5c1..7808a4b2dc74 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
@@ -29,6 +29,7 @@ import android.view.animation.PathInterpolator;
import android.widget.ImageView;
import android.widget.TextView;
+import com.android.internal.widget.CachingIconView;
import com.android.internal.widget.NotificationExpandButton;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -54,7 +55,7 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
protected int mColor;
- private ImageView mIcon;
+ private CachingIconView mIcon;
private NotificationExpandButton mExpandButton;
protected NotificationHeaderView mNotificationHeader;
private TextView mHeaderText;
@@ -199,6 +200,22 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
}
@Override
+ public int getOriginalIconColor() {
+ return mIcon.getOriginalIconColor();
+ }
+
+ @Override
+ public View getShelfTransformationTarget() {
+ return mIcon;
+ }
+
+ @Override
+ public void setShelfIconVisible(boolean visible) {
+ super.setShelfIconVisible(visible);
+ mIcon.setForceHidden(visible);
+ }
+
+ @Override
public TransformState getCurrentState(int fadingView) {
return mTransformationHelper.getCurrentState(fadingView);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
index 46d7d9374290..e4fb2f7c42d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.row.wrapper;
import android.annotation.ColorInt;
+import android.annotation.Nullable;
import android.app.Notification;
import android.content.Context;
import android.content.res.Configuration;
@@ -230,6 +231,22 @@ public abstract class NotificationViewWrapper implements TransformableView {
return null;
}
+ public int getOriginalIconColor() {
+ return Notification.COLOR_INVALID;
+ }
+
+ /**
+ * @return get the transformation target of the shelf, which usually is the icon
+ */
+ public @Nullable View getShelfTransformationTarget() {
+ return null;
+ }
+
+ /**
+ * Set the shelf icon to be visible and hide our own icons.
+ */
+ public void setShelfIconVisible(boolean shelfIconVisible) {}
+
public int getHeaderTranslation(boolean forceNoHeader) {
return 0;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationProperties.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationProperties.java
index 87a3cc9d2db8..112d48c115c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationProperties.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationProperties.java
@@ -16,12 +16,15 @@
package com.android.systemui.statusbar.notification.stack;
+import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.util.ArrayMap;
import android.util.Property;
import android.view.View;
import android.view.animation.Interpolator;
+import java.util.function.Consumer;
+
/**
* Properties for a View animation
*/
@@ -29,7 +32,7 @@ public class AnimationProperties {
public long duration;
public long delay;
private ArrayMap<Property, Interpolator> mInterpolatorMap;
- private AnimatorListenerAdapter mAnimatorListenerAdapter;
+ private Consumer<Property> mAnimationEndAction;
/**
* @return an animation filter for this animation.
@@ -44,14 +47,32 @@ public class AnimationProperties {
}
/**
- * @return a listener that should be run whenever any property finished its animation
+ * @return a listener that will be added for a given property during its animation.
*/
- public AnimatorListenerAdapter getAnimationFinishListener() {
- return mAnimatorListenerAdapter;
+ public AnimatorListenerAdapter getAnimationFinishListener(Property property) {
+ if (mAnimationEndAction == null) {
+ return null;
+ }
+ Consumer<Property> endAction = mAnimationEndAction;
+ return new AnimatorListenerAdapter() {
+ private boolean mCancelled;
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCancelled = true;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (!mCancelled) {
+ endAction.accept(property);
+ }
+ }
+ };
}
- public AnimationProperties setAnimationFinishListener(AnimatorListenerAdapter listener) {
- mAnimatorListenerAdapter = listener;
+ public AnimationProperties setAnimationEndAction(Consumer<Property> listener) {
+ mAnimationEndAction = listener;
return this;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java
index 72ef7f9572a4..628c4e258e50 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java
@@ -263,7 +263,8 @@ public class ExpandableViewState extends ViewState {
|| previousAnimator.getAnimatedFraction() == 0)) {
animator.setStartDelay(properties.delay);
}
- AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
+ AnimatorListenerAdapter listener = properties.getAnimationFinishListener(
+ null /* no property for this height */);
if (listener != null) {
animator.addListener(listener);
}
@@ -343,7 +344,8 @@ public class ExpandableViewState extends ViewState {
|| previousAnimator.getAnimatedFraction() == 0)) {
animator.setStartDelay(properties.delay);
}
- AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
+ AnimatorListenerAdapter listener = properties.getAnimationFinishListener(
+ null /* no property for top inset */);
if (listener != null) {
animator.addListener(listener);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index 2c17764799a5..3d0bf3f4c1c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -1187,18 +1187,18 @@ public class NotificationChildrenContainer extends ViewGroup {
return 0;
}
- public void setIconsVisible(boolean iconsVisible) {
+ public void setShelfIconVisible(boolean iconVisible) {
if (mNotificationHeaderWrapper != null) {
NotificationHeaderView header = mNotificationHeaderWrapper.getNotificationHeader();
if (header != null) {
- header.getIcon().setForceHidden(!iconsVisible);
+ header.getIcon().setForceHidden(iconVisible);
}
}
if (mNotificationHeaderWrapperLowPriority != null) {
NotificationHeaderView header
= mNotificationHeaderWrapperLowPriority.getNotificationHeader();
if (header != null) {
- header.getIcon().setForceHidden(!iconsVisible);
+ header.getIcon().setForceHidden(iconVisible);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
index 14442e346db4..77850826a5e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
@@ -104,7 +104,7 @@ public class StackStateAnimator {
}
@Override
- public AnimatorListenerAdapter getAnimationFinishListener() {
+ public AnimatorListenerAdapter getAnimationFinishListener(Property property) {
return getGlobalAnimationFinishedListener();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
index b00068cd2445..3da4e321c54d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
@@ -393,7 +393,7 @@ public class ViewState implements Dumpable {
|| previousAnimator.getAnimatedFraction() == 0)) {
animator.setStartDelay(properties.delay);
}
- AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
+ AnimatorListenerAdapter listener = properties.getAnimationFinishListener(View.ALPHA);
if (listener != null) {
animator.addListener(listener);
}
@@ -450,7 +450,8 @@ public class ViewState implements Dumpable {
|| previousAnimator.getAnimatedFraction() == 0)) {
animator.setStartDelay(properties.delay);
}
- AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
+ AnimatorListenerAdapter listener = properties.getAnimationFinishListener(
+ View.TRANSLATION_Z);
if (listener != null) {
animator.addListener(listener);
}
@@ -515,7 +516,8 @@ public class ViewState implements Dumpable {
|| previousAnimator.getAnimatedFraction() == 0)) {
animator.setStartDelay(properties.delay);
}
- AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
+ AnimatorListenerAdapter listener = properties.getAnimationFinishListener(
+ View.TRANSLATION_X);
if (listener != null) {
animator.addListener(listener);
}
@@ -580,7 +582,8 @@ public class ViewState implements Dumpable {
|| previousAnimator.getAnimatedFraction() == 0)) {
animator.setStartDelay(properties.delay);
}
- AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
+ AnimatorListenerAdapter listener = properties.getAnimationFinishListener(
+ View.TRANSLATION_Y);
if (listener != null) {
animator.addListener(listener);
}
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 a53ce9bb2014..07eaaa187fbe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -19,6 +19,8 @@ package com.android.systemui.statusbar.phone;
import static com.android.systemui.statusbar.phone.HeadsUpAppearanceController.CONTENT_FADE_DELAY;
import static com.android.systemui.statusbar.phone.HeadsUpAppearanceController.CONTENT_FADE_DURATION;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Canvas;
@@ -27,7 +29,9 @@ import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Icon;
import android.util.AttributeSet;
+import android.util.Property;
import android.view.View;
+import android.view.animation.Interpolator;
import androidx.collection.ArrayMap;
@@ -42,6 +46,7 @@ import com.android.systemui.statusbar.notification.stack.ViewState;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.function.Consumer;
/**
* A container for notification icons. It handles overflowing icons properly and positions them
@@ -69,7 +74,10 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
}.setDuration(200);
private static final AnimationProperties ICON_ANIMATION_PROPERTIES = new AnimationProperties() {
- private AnimationFilter mAnimationFilter = new AnimationFilter().animateY().animateAlpha()
+ private AnimationFilter mAnimationFilter = new AnimationFilter()
+ .animateX()
+ .animateY()
+ .animateAlpha()
.animateScale();
@Override
@@ -77,8 +85,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
return mAnimationFilter;
}
- }.setDuration(CANNED_ANIMATION_DURATION)
- .setCustomInterpolator(View.TRANSLATION_Y, Interpolators.ICON_OVERSHOT);
+ }.setDuration(CANNED_ANIMATION_DURATION);
/**
* Temporary AnimationProperties to avoid unnecessary allocations.
@@ -272,7 +279,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
super.onViewAdded(child);
boolean isReplacingIcon = isReplacingIcon(child);
if (!mChangingViewPositions) {
- IconState v = new IconState();
+ IconState v = new IconState(child);
if (isReplacingIcon) {
v.justAdded = false;
v.justReplaced = true;
@@ -388,7 +395,12 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
for (int i = 0; i < childCount; i++) {
View view = getChildAt(i);
IconState iconState = mIconStates.get(view);
- iconState.xTranslation = translationX;
+ if (iconState.iconAppearAmount == 1.0f) {
+ // We only modify the xTranslation if it's fully inside of the container
+ // since during the transition to the shelf, the translations are controlled
+ // from the outside
+ iconState.xTranslation = translationX;
+ }
if (mFirstVisibleIconState == null) {
mFirstVisibleIconState = iconState;
}
@@ -499,7 +511,10 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
return mActualPaddingEnd;
}
- private float getActualPaddingStart() {
+ /**
+ * @return the actual startPadding of this view
+ */
+ public float getActualPaddingStart() {
if (mActualPaddingStart == NO_VALUE) {
return getPaddingStart();
}
@@ -692,6 +707,20 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
public boolean noAnimations;
public boolean isLastExpandIcon;
public int customTransformHeight = NO_VALUE;
+ private final View mView;
+
+ private final Consumer<Property> mCannedAnimationEndListener;
+
+ public IconState(View child) {
+ mView = child;
+ mCannedAnimationEndListener = (property) -> {
+ // If we finished animating out of the shelf
+ if (property == View.TRANSLATION_Y && iconAppearAmount == 0.0f
+ && mView.getVisibility() == VISIBLE) {
+ mView.setVisibility(INVISIBLE);
+ }
+ };
+ }
@Override
public void applyToView(View view) {
@@ -729,6 +758,14 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
ICON_ANIMATION_PROPERTIES.getAnimationFilter());
sTempProperties.resetCustomInterpolators();
sTempProperties.combineCustomInterpolators(ICON_ANIMATION_PROPERTIES);
+ Interpolator interpolator;
+ if (icon.showsConversation()) {
+ interpolator = Interpolators.ICON_OVERSHOT_LESS;
+ } else {
+ interpolator = Interpolators.ICON_OVERSHOT;
+ }
+ sTempProperties.setCustomInterpolator(View.TRANSLATION_Y, interpolator);
+ sTempProperties.setAnimationEndAction(mCannedAnimationEndListener);
if (animationProperties != null) {
animationFilter.combineFilter(animationProperties.getAnimationFilter());
sTempProperties.combineCustomInterpolators(animationProperties);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 5588c24f2fd6..98ba6e5b88a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -379,14 +379,6 @@ public class NotificationPanelViewController extends PanelViewController {
private Runnable mPanelAlphaEndAction;
private float mBottomAreaShadeAlpha;
private final ValueAnimator mBottomAreaShadeAlphaAnimator;
- private AnimatorListenerAdapter mAnimatorListenerAdapter = new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- if (mPanelAlphaEndAction != null) {
- mPanelAlphaEndAction.run();
- }
- }
- };
private final AnimatableProperty mPanelAlphaAnimator = AnimatableProperty.from("panelAlpha",
NotificationPanelView::setPanelAlphaInternal,
NotificationPanelView::getCurrentPanelAlpha,
@@ -396,8 +388,11 @@ public class NotificationPanelViewController extends PanelViewController {
new AnimationProperties().setDuration(150).setCustomInterpolator(
mPanelAlphaAnimator.getProperty(), Interpolators.ALPHA_OUT);
private final AnimationProperties mPanelAlphaInPropertiesAnimator =
- new AnimationProperties().setDuration(200).setAnimationFinishListener(
- mAnimatorListenerAdapter).setCustomInterpolator(
+ new AnimationProperties().setDuration(200).setAnimationEndAction((property) -> {
+ if (mPanelAlphaEndAction != null) {
+ mPanelAlphaEndAction.run();
+ }
+ }).setCustomInterpolator(
mPanelAlphaAnimator.getProperty(), Interpolators.ALPHA_IN);
private final NotificationEntryManager mEntryManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
index 6359234fa6ba..57278e32d553 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
@@ -93,7 +93,7 @@ public class PropertyAnimatorTest extends SysuiTestCase {
}
@Override
- public AnimatorListenerAdapter getAnimationFinishListener() {
+ public AnimatorListenerAdapter getAnimationFinishListener(Property property) {
return mFinishListener;
}
}.setDuration(200);