Loading core/res/res/layout/notification_template_right_icon.xml +4 −2 Original line number Diff line number Diff line Loading @@ -26,8 +26,9 @@ android:layout_gravity="top|end" android:layout_marginTop="36dp" android:layout_marginEnd="@dimen/notification_content_margin_end" android:scaleType="centerCrop"/> <ImageView android:id="@+id/reply_icon_action" android:scaleType="centerCrop" android:importantForAccessibility="no" /> <ImageButton android:id="@+id/reply_icon_action" android:layout_width="16dp" android:layout_height="16dp" android:layout_gravity="top|end" Loading @@ -36,6 +37,7 @@ android:background="@drawable/notification_reply_background" android:src="@drawable/ic_reply_notification" android:scaleType="center" android:contentDescription="@string/notification_reply_button_accessibility" visiblity="gone"/> </FrameLayout> core/res/res/values/strings.xml +3 −0 Original line number Diff line number Diff line Loading @@ -4671,6 +4671,9 @@ <!-- Primary ETWS (Earthquake and Tsunami Warning System) default message for test --> <string name="etws_primary_default_message_test">Emergency messages test</string> <!-- Content description for the reply button in the notification area [CHAR LIMIT=NONE]--> <string name="notification_reply_button_accessibility">Reply</string> <!-- Primary ETWS (Earthquake and Tsunami Warning System) default message for others --> <string name="etws_primary_default_message_others"></string> Loading packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +60 −8 Original line number Diff line number Diff line Loading @@ -16,15 +16,18 @@ package com.android.systemui.statusbar; import static com.android.systemui.statusbar.phone.NotificationIconContainer.IconState.NO_VALUE; import static com.android.systemui.statusbar.phone.NotificationIconContainer.OVERFLOW_EARLY_AMOUNT; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; import android.os.SystemProperties; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.accessibility.AccessibilityNodeInfo; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.ViewInvertHelper; Loading Loading @@ -315,26 +318,65 @@ public class NotificationShelf extends ActivatableNotificationView implements private float updateIconAppearance(ExpandableNotificationRow row, float expandAmount, boolean scrolling, boolean scrollingFast, boolean expandingAnimated, boolean isLastChild) { StatusBarIconView icon = row.getEntry().expandedIcon; NotificationIconContainer.IconState iconState = getIconState(icon); if (iconState == null) { return 0.0f; } // Let calculate how much the view is in the shelf float viewStart = row.getTranslationY(); int fullHeight = row.getActualHeight() + mPaddingBetweenElements; float iconTransformDistance = getIntrinsicHeight() * 1.5f; iconTransformDistance *= NotificationUtils.interpolate(1.f, 1.5f, expandAmount); iconTransformDistance = Math.min(iconTransformDistance, fullHeight); if (isLastChild) { fullHeight = Math.min(fullHeight, row.getMinHeight() - getIntrinsicHeight()); iconTransformDistance = Math.min(iconTransformDistance, row.getMinHeight() - getIntrinsicHeight()); } float viewEnd = viewStart + fullHeight; if (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(row); int maxShelfStart = mMaxLayoutHeight - getIntrinsicHeight(); if (position < maxShelfStart && position + row.getIntrinsicHeight() >= maxShelfStart && row.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); } } } float fullTransitionAmount; float iconTransitionAmount; float shelfStart = getTranslationY(); if (iconState.hasCustomTransformHeight()) { fullHeight = iconState.customTransformHeight; iconTransformDistance = iconState.customTransformHeight; } boolean fullyInOrOut = true; if (viewEnd >= shelfStart && (!mAmbientState.isUnlockHintRunning() || row.isInShelf()) && (mAmbientState.isShadeExpanded() || (!row.isPinned() && !row.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( Loading @@ -344,7 +386,7 @@ public class NotificationShelf extends ActivatableNotificationView implements iconTransitionAmount = (shelfStart - viewStart) / iconTransformDistance; iconTransitionAmount = Math.min(1.0f, iconTransitionAmount); iconTransitionAmount = 1.0f - iconTransitionAmount; fullyInOrOut = false; } else { fullTransitionAmount = 1.0f; iconTransitionAmount = 1.0f; Loading @@ -353,6 +395,10 @@ public class NotificationShelf extends ActivatableNotificationView implements fullTransitionAmount = 0.0f; iconTransitionAmount = 0.0f; } if (fullyInOrOut && !expandingAnimated && iconState.isLastExpandIcon) { iconState.isLastExpandIcon = false; iconState.customTransformHeight = NO_VALUE; } updateIconPositioning(row, iconTransitionAmount, fullTransitionAmount, iconTransformDistance, scrolling, scrollingFast, expandingAnimated, isLastChild); return fullTransitionAmount; Loading @@ -366,9 +412,10 @@ public class NotificationShelf extends ActivatableNotificationView implements if (iconState == null) { return; } boolean forceInShelf = iconState.isLastExpandIcon && !iconState.hasCustomTransformHeight(); float clampedAmount = iconTransitionAmount > 0.5f ? 1.0f : 0.0f; if (clampedAmount == fullTransitionAmount) { iconState.noAnimations = scrollingFast || expandingAnimated; iconState.noAnimations = (scrollingFast || expandingAnimated) && !forceInShelf; iconState.useFullTransitionAmount = iconState.noAnimations || (!ICON_ANMATIONS_WHILE_SCROLLING && fullTransitionAmount == 0.0f && scrolling); iconState.useLinearTransitionAmount = !ICON_ANMATIONS_WHILE_SCROLLING Loading @@ -376,12 +423,18 @@ public class NotificationShelf extends ActivatableNotificationView implements iconState.translateContent = mMaxLayoutHeight - getTranslationY() - getIntrinsicHeight() > 0; } if (scrollingFast || (expandingAnimated && iconState.useFullTransitionAmount && !ViewState.isAnimatingY(icon))) { 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 (isLastChild || !USE_ANIMATIONS_WHEN_OPENING || iconState.useFullTransitionAmount || iconState.useLinearTransitionAmount) { Loading Loading @@ -548,8 +601,7 @@ public class NotificationShelf extends ActivatableNotificationView implements if (!hasOverflow) { // we have to ensure that adding the low priority notification won't lead to an // overflow collapsedPadding -= (1.0f + NotificationIconContainer.OVERFLOW_EARLY_AMOUNT) * mCollapsedIcons.getIconSize(); collapsedPadding -= (1.0f + OVERFLOW_EARLY_AMOUNT) * mCollapsedIcons.getIconSize(); } float padding = NotificationUtils.interpolate(collapsedPadding, mShelfIcons.getPaddingEnd(), Loading packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java +7 −0 Original line number Diff line number Diff line Loading @@ -526,6 +526,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { } public class IconState extends ViewState { public static final int NO_VALUE = NotificationIconContainer.NO_VALUE; public float iconAppearAmount = 1.0f; public float clampedAppearAmount = 1.0f; public int visibleState; Loading @@ -538,6 +539,8 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { public boolean justUndarkened; public int iconColor = StatusBarIconView.NO_COLOR; public boolean noAnimations; public boolean isLastExpandIcon; public int customTransformHeight = NO_VALUE; @Override public void applyToView(View view) { Loading Loading @@ -615,6 +618,10 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { justUndarkened = false; } public boolean hasCustomTransformHeight() { return isLastExpandIcon && customTransformHeight != NO_VALUE; } @Override public void initFrom(View view) { super.initFrom(view); Loading packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java +9 −0 Original line number Diff line number Diff line Loading @@ -62,6 +62,7 @@ public class AmbientState { private boolean mHasPulsingNotifications; private boolean mUnlockHintRunning; private boolean mQsCustomizerShowing; private int mIntrinsicPadding; public AmbientState(Context context) { reload(context); Loading Loading @@ -323,4 +324,12 @@ public class AmbientState { public void setQsCustomizerShowing(boolean qsCustomizerShowing) { mQsCustomizerShowing = qsCustomizerShowing; } public void setIntrinsicPadding(int intrinsicPadding) { mIntrinsicPadding = intrinsicPadding; } public int getIntrinsicPadding() { return mIntrinsicPadding; } } Loading
core/res/res/layout/notification_template_right_icon.xml +4 −2 Original line number Diff line number Diff line Loading @@ -26,8 +26,9 @@ android:layout_gravity="top|end" android:layout_marginTop="36dp" android:layout_marginEnd="@dimen/notification_content_margin_end" android:scaleType="centerCrop"/> <ImageView android:id="@+id/reply_icon_action" android:scaleType="centerCrop" android:importantForAccessibility="no" /> <ImageButton android:id="@+id/reply_icon_action" android:layout_width="16dp" android:layout_height="16dp" android:layout_gravity="top|end" Loading @@ -36,6 +37,7 @@ android:background="@drawable/notification_reply_background" android:src="@drawable/ic_reply_notification" android:scaleType="center" android:contentDescription="@string/notification_reply_button_accessibility" visiblity="gone"/> </FrameLayout>
core/res/res/values/strings.xml +3 −0 Original line number Diff line number Diff line Loading @@ -4671,6 +4671,9 @@ <!-- Primary ETWS (Earthquake and Tsunami Warning System) default message for test --> <string name="etws_primary_default_message_test">Emergency messages test</string> <!-- Content description for the reply button in the notification area [CHAR LIMIT=NONE]--> <string name="notification_reply_button_accessibility">Reply</string> <!-- Primary ETWS (Earthquake and Tsunami Warning System) default message for others --> <string name="etws_primary_default_message_others"></string> Loading
packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +60 −8 Original line number Diff line number Diff line Loading @@ -16,15 +16,18 @@ package com.android.systemui.statusbar; import static com.android.systemui.statusbar.phone.NotificationIconContainer.IconState.NO_VALUE; import static com.android.systemui.statusbar.phone.NotificationIconContainer.OVERFLOW_EARLY_AMOUNT; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; import android.os.SystemProperties; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.accessibility.AccessibilityNodeInfo; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.ViewInvertHelper; Loading Loading @@ -315,26 +318,65 @@ public class NotificationShelf extends ActivatableNotificationView implements private float updateIconAppearance(ExpandableNotificationRow row, float expandAmount, boolean scrolling, boolean scrollingFast, boolean expandingAnimated, boolean isLastChild) { StatusBarIconView icon = row.getEntry().expandedIcon; NotificationIconContainer.IconState iconState = getIconState(icon); if (iconState == null) { return 0.0f; } // Let calculate how much the view is in the shelf float viewStart = row.getTranslationY(); int fullHeight = row.getActualHeight() + mPaddingBetweenElements; float iconTransformDistance = getIntrinsicHeight() * 1.5f; iconTransformDistance *= NotificationUtils.interpolate(1.f, 1.5f, expandAmount); iconTransformDistance = Math.min(iconTransformDistance, fullHeight); if (isLastChild) { fullHeight = Math.min(fullHeight, row.getMinHeight() - getIntrinsicHeight()); iconTransformDistance = Math.min(iconTransformDistance, row.getMinHeight() - getIntrinsicHeight()); } float viewEnd = viewStart + fullHeight; if (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(row); int maxShelfStart = mMaxLayoutHeight - getIntrinsicHeight(); if (position < maxShelfStart && position + row.getIntrinsicHeight() >= maxShelfStart && row.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); } } } float fullTransitionAmount; float iconTransitionAmount; float shelfStart = getTranslationY(); if (iconState.hasCustomTransformHeight()) { fullHeight = iconState.customTransformHeight; iconTransformDistance = iconState.customTransformHeight; } boolean fullyInOrOut = true; if (viewEnd >= shelfStart && (!mAmbientState.isUnlockHintRunning() || row.isInShelf()) && (mAmbientState.isShadeExpanded() || (!row.isPinned() && !row.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( Loading @@ -344,7 +386,7 @@ public class NotificationShelf extends ActivatableNotificationView implements iconTransitionAmount = (shelfStart - viewStart) / iconTransformDistance; iconTransitionAmount = Math.min(1.0f, iconTransitionAmount); iconTransitionAmount = 1.0f - iconTransitionAmount; fullyInOrOut = false; } else { fullTransitionAmount = 1.0f; iconTransitionAmount = 1.0f; Loading @@ -353,6 +395,10 @@ public class NotificationShelf extends ActivatableNotificationView implements fullTransitionAmount = 0.0f; iconTransitionAmount = 0.0f; } if (fullyInOrOut && !expandingAnimated && iconState.isLastExpandIcon) { iconState.isLastExpandIcon = false; iconState.customTransformHeight = NO_VALUE; } updateIconPositioning(row, iconTransitionAmount, fullTransitionAmount, iconTransformDistance, scrolling, scrollingFast, expandingAnimated, isLastChild); return fullTransitionAmount; Loading @@ -366,9 +412,10 @@ public class NotificationShelf extends ActivatableNotificationView implements if (iconState == null) { return; } boolean forceInShelf = iconState.isLastExpandIcon && !iconState.hasCustomTransformHeight(); float clampedAmount = iconTransitionAmount > 0.5f ? 1.0f : 0.0f; if (clampedAmount == fullTransitionAmount) { iconState.noAnimations = scrollingFast || expandingAnimated; iconState.noAnimations = (scrollingFast || expandingAnimated) && !forceInShelf; iconState.useFullTransitionAmount = iconState.noAnimations || (!ICON_ANMATIONS_WHILE_SCROLLING && fullTransitionAmount == 0.0f && scrolling); iconState.useLinearTransitionAmount = !ICON_ANMATIONS_WHILE_SCROLLING Loading @@ -376,12 +423,18 @@ public class NotificationShelf extends ActivatableNotificationView implements iconState.translateContent = mMaxLayoutHeight - getTranslationY() - getIntrinsicHeight() > 0; } if (scrollingFast || (expandingAnimated && iconState.useFullTransitionAmount && !ViewState.isAnimatingY(icon))) { 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 (isLastChild || !USE_ANIMATIONS_WHEN_OPENING || iconState.useFullTransitionAmount || iconState.useLinearTransitionAmount) { Loading Loading @@ -548,8 +601,7 @@ public class NotificationShelf extends ActivatableNotificationView implements if (!hasOverflow) { // we have to ensure that adding the low priority notification won't lead to an // overflow collapsedPadding -= (1.0f + NotificationIconContainer.OVERFLOW_EARLY_AMOUNT) * mCollapsedIcons.getIconSize(); collapsedPadding -= (1.0f + OVERFLOW_EARLY_AMOUNT) * mCollapsedIcons.getIconSize(); } float padding = NotificationUtils.interpolate(collapsedPadding, mShelfIcons.getPaddingEnd(), Loading
packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java +7 −0 Original line number Diff line number Diff line Loading @@ -526,6 +526,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { } public class IconState extends ViewState { public static final int NO_VALUE = NotificationIconContainer.NO_VALUE; public float iconAppearAmount = 1.0f; public float clampedAppearAmount = 1.0f; public int visibleState; Loading @@ -538,6 +539,8 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { public boolean justUndarkened; public int iconColor = StatusBarIconView.NO_COLOR; public boolean noAnimations; public boolean isLastExpandIcon; public int customTransformHeight = NO_VALUE; @Override public void applyToView(View view) { Loading Loading @@ -615,6 +618,10 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { justUndarkened = false; } public boolean hasCustomTransformHeight() { return isLastExpandIcon && customTransformHeight != NO_VALUE; } @Override public void initFrom(View view) { super.initFrom(view); Loading
packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java +9 −0 Original line number Diff line number Diff line Loading @@ -62,6 +62,7 @@ public class AmbientState { private boolean mHasPulsingNotifications; private boolean mUnlockHintRunning; private boolean mQsCustomizerShowing; private int mIntrinsicPadding; public AmbientState(Context context) { reload(context); Loading Loading @@ -323,4 +324,12 @@ public class AmbientState { public void setQsCustomizerShowing(boolean qsCustomizerShowing) { mQsCustomizerShowing = qsCustomizerShowing; } public void setIntrinsicPadding(int intrinsicPadding) { mIntrinsicPadding = intrinsicPadding; } public int getIntrinsicPadding() { return mIntrinsicPadding; } }