Merge "Merge changes I0d79642d,If8756ac8,I29e73897,Ia8c5121a,I533b8f06 into rvc-dev am: 9bad85af2b am: 3bd1a83e56" into rvc-d1-dev-plus-aosp
This commit is contained in:
committed by
Android (Google) Code Review
commit
36bf20dfa6
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -3896,6 +3896,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 -->
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,16 +537,107 @@ 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.
|
||||
handleCustomTransformHeight(view, expandingAnimated, iconState);
|
||||
|
||||
float fullTransitionAmount;
|
||||
float transitionAmount;
|
||||
float contentTransformationAmount;
|
||||
float shelfStart = getTranslationY();
|
||||
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(
|
||||
fullAmount);
|
||||
interpolatedAmount = NotificationUtils.interpolate(
|
||||
interpolatedAmount, fullAmount, expandAmount);
|
||||
fullTransitionAmount = 1.0f - interpolatedAmount;
|
||||
|
||||
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,
|
||||
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,
|
||||
@@ -573,45 +665,6 @@ public class NotificationShelf extends ActivatableNotificationView implements
|
||||
}
|
||||
}
|
||||
}
|
||||
float fullTransitionAmount;
|
||||
float transitionAmount;
|
||||
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) {
|
||||
float fullAmount = (shelfStart - viewStart) / fullHeight;
|
||||
fullAmount = Math.min(1.0f, fullAmount);
|
||||
float interpolatedAmount = Interpolators.ACCELERATE_DECELERATE.getInterpolation(
|
||||
fullAmount);
|
||||
interpolatedAmount = NotificationUtils.interpolate(
|
||||
interpolatedAmount, fullAmount, expandAmount);
|
||||
fullTransitionAmount = 1.0f - interpolatedAmount;
|
||||
|
||||
transitionAmount = (shelfStart - viewStart) / iconTransformDistance;
|
||||
transitionAmount = Math.min(1.0f, transitionAmount);
|
||||
transitionAmount = 1.0f - transitionAmount;
|
||||
fullyInOrOut = false;
|
||||
} else {
|
||||
fullTransitionAmount = 1.0f;
|
||||
transitionAmount = 1.0f;
|
||||
}
|
||||
} else {
|
||||
fullTransitionAmount = 0.0f;
|
||||
transitionAmount = 0.0f;
|
||||
}
|
||||
if (iconState != null && fullyInOrOut && !expandingAnimated && iconState.isLastExpandIcon) {
|
||||
iconState.isLastExpandIcon = false;
|
||||
iconState.customTransformHeight = NO_VALUE;
|
||||
}
|
||||
updateIconPositioning(view, transitionAmount, fullTransitionAmount,
|
||||
iconTransformDistance, scrolling, scrollingFast, expandingAnimated, isLastChild);
|
||||
return fullTransitionAmount;
|
||||
}
|
||||
|
||||
private void updateIconPositioning(ExpandableView view, float iconTransitionAmount,
|
||||
@@ -619,61 +672,69 @@ public class NotificationShelf extends ActivatableNotificationView implements
|
||||
boolean scrollingFast, boolean expandingAnimated, boolean isLastChild) {
|
||||
StatusBarIconView icon = view.getShelfIcon();
|
||||
NotificationIconContainer.IconState iconState = getIconState(icon);
|
||||
float contentTransformationAmount;
|
||||
if (iconState == null) {
|
||||
contentTransformationAmount = 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);
|
||||
return;
|
||||
}
|
||||
view.setContentTransformationAmount(contentTransformationAmount, isLastChild);
|
||||
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 {
|
||||
// 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;
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,39 +1520,16 @@ 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);
|
||||
mChildrenContainer.setShelfIconVisible(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;
|
||||
}
|
||||
}
|
||||
return topPadding;
|
||||
}
|
||||
|
||||
public float getContentTranslation() {
|
||||
return mPrivateLayout.getTranslationY();
|
||||
}
|
||||
|
||||
public void setIsLowPriority(boolean isLowPriority) {
|
||||
mIsLowPriority = isLowPriority;
|
||||
mPrivateLayout.setIsLowPriority(isLowPriority);
|
||||
@@ -2134,7 +2100,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatusBarIconView getShelfIcon() {
|
||||
public @NonNull StatusBarIconView getShelfIcon() {
|
||||
return getEntry().getIcons().getShelfIcon();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
@@ -635,6 +636,56 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*
|
||||
@@ -665,6 +716,7 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable {
|
||||
if (mIsLastChild) {
|
||||
translationY *= 0.4f;
|
||||
}
|
||||
mContentTranslation = translationY;
|
||||
applyContentTransformation(contentAlpha, translationY);
|
||||
}
|
||||
|
||||
@@ -708,6 +760,13 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable {
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
}
|
||||
|
||||
/**
|
||||
* return the amount that the content is translated
|
||||
*/
|
||||
public float getContentTranslation() {
|
||||
return mContentTranslation;
|
||||
}
|
||||
|
||||
/**
|
||||
* A listener notifying when {@link #getActualHeight} changes.
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -198,6 +199,22 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
|
||||
return mNotificationHeader;
|
||||
}
|
||||
|
||||
@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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ public class StackStateAnimator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnimatorListenerAdapter getAnimationFinishListener() {
|
||||
public AnimatorListenerAdapter getAnimationFinishListener(Property property) {
|
||||
return getGlobalAnimationFinishedListener();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ public class PropertyAnimatorTest extends SysuiTestCase {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnimatorListenerAdapter getAnimationFinishListener() {
|
||||
public AnimatorListenerAdapter getAnimationFinishListener(Property property) {
|
||||
return mFinishListener;
|
||||
}
|
||||
}.setDuration(200);
|
||||
|
||||
Reference in New Issue
Block a user