Loading core/java/android/app/Notification.java +23 −4 Original line number Diff line number Diff line Loading @@ -6321,6 +6321,13 @@ public class Notification implements Parcelable // If there is no title, the text (or big_text) needs to wrap around the image result.mTitleMarginSet.applyToView(contentView, p.mTextViewId); contentView.setInt(p.mTextViewId, "setNumIndentLines", p.hasTitle() ? 0 : 1); } else if (notificationsRedesignTemplates() && !p.mCompact) { // In the collapsed view (except for compact HUNs), the top line needs to // accommodate both the expander and large icon (when present) result.mHeadingFullMarginSet.applyToView(contentView, R.id.notification_top_line); // The text underneath can flow below the expander, but only if there's no large // icon to leave space for (similar to the title in the expanded version). result.mTitleMarginSet.applyToView(contentView, R.id.notification_main_column); } // The expand button uses paddings rather than margins, so we'll adjust it // separately. Loading Loading @@ -6435,7 +6442,7 @@ public class Notification implements Parcelable contentView.setImageViewIcon(R.id.right_icon, rightIcon); contentView.setIntTag(R.id.right_icon, R.id.tag_keep_when_showing_left_icon, isPromotedPicture ? 1 : 0); if ((notificationsRedesignTemplates() || Flags.uiRichOngoing()) && !p.mHeaderless) { if (notificationsRedesignTemplates() || Flags.uiRichOngoing()) { contentView.setViewLayoutMargin(R.id.right_icon, RemoteViews.MARGIN_END, getLargeIconMarginEnd(p), COMPLEX_UNIT_PX); } Loading Loading @@ -6464,7 +6471,7 @@ public class Notification implements Parcelable if (notificationsRedesignTemplates()) { int rightIconMarginPx = res.getDimensionPixelSize( R.dimen.notification_2025_right_icon_expanded_margin_end); R.dimen.notification_2025_right_icon_margin_end); int extraSpaceForExpanderPx = res.getDimensionPixelSize( R.dimen.notification_2025_extra_space_for_expander); return rightIconMarginPx + extraSpaceForExpanderPx; Loading Loading @@ -7172,6 +7179,7 @@ public class Notification implements Parcelable final StandardTemplateParams p = mParams.reset() .viewType(StandardTemplateParams.VIEW_TYPE_HEADS_UP) .compact(true) .fillTextsFrom(this); // Notification text is shown as secondary header text // for the minimal hun when it is provided. Loading Loading @@ -8435,8 +8443,12 @@ public class Notification implements Parcelable // ensures that we don't under-pad the content, which could lead to abuse, at the // cost of making single-line custom content over-padded. Builder.setHeaderlessVerticalMargins(template, p, true /* hasSecondLine */); } else { if (notificationsRedesignTemplates()) { // also update the end margin to account for the large icon or expander result.mHeadingFullMarginSet.applyToView(template, R.id.notification_main_column); } } else { Resources resources = context.getResources(); result.mTitleMarginSet.applyToView(template, R.id.notification_main_column, resources.getDimension(R.dimen.notification_content_margin_end) Loading Loading @@ -16505,6 +16517,7 @@ public class Notification implements Parcelable int mViewType = VIEW_TYPE_UNSPECIFIED; boolean mHeaderless; boolean mCompact; boolean mHideAppName; boolean mHideTitle; boolean mHideSubText; Loading @@ -16530,6 +16543,7 @@ public class Notification implements Parcelable final StandardTemplateParams reset() { mViewType = VIEW_TYPE_UNSPECIFIED; mHeaderless = false; mCompact = false; mHideAppName = false; mHideTitle = false; mHideSubText = false; Loading Loading @@ -16568,6 +16582,11 @@ public class Notification implements Parcelable return this; } public StandardTemplateParams compact(boolean compact) { mCompact = compact; return this; } public StandardTemplateParams hideAppName(boolean hideAppName) { mHideAppName = hideAppName; return this; core/java/com/android/internal/widget/ConversationLayout.java +65 −14 Original line number Diff line number Diff line Loading @@ -34,7 +34,6 @@ import android.app.Person; import android.app.RemoteInputHistoryItem; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Resources; import android.graphics.Rect; import android.graphics.Typeface; import android.graphics.drawable.Drawable; Loading @@ -49,8 +48,10 @@ import android.text.style.StyleSpan; import android.util.ArrayMap; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.view.Gravity; import android.view.MotionEvent; import android.view.NotificationTopLineView; import android.view.RemotableViewMethod; import android.view.TouchDelegate; import android.view.View; Loading Loading @@ -86,6 +87,7 @@ public class ConversationLayout extends FrameLayout public static final Interpolator FAST_OUT_LINEAR_IN = new PathInterpolator(0.4f, 0f, 1f, 1f); public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f); public static final Interpolator OVERSHOOT = new PathInterpolator(0.4f, 0f, 0.2f, 1.4f); private static final String TAG = "ConversationLayout"; private static final int MAX_SUMMARIZATION_LINES = 3; public static final int IMPORTANCE_ANIM_GROW_DURATION = 250; public static final int IMPORTANCE_ANIM_SHRINK_DURATION = 200; Loading Loading @@ -123,6 +125,7 @@ public class ConversationLayout extends FrameLayout private ViewGroup mExpandButtonAndContentContainer; private ViewGroup mExpandButtonContainerA11yContainer; private NotificationExpandButton mExpandButton; private NotificationTopLineView mTopLine; private MessagingLinearLayout mImageMessageContainer; private ImageView mRightIconView; private int mBadgeProtrusion; Loading Loading @@ -271,6 +274,7 @@ public class ConversationLayout extends FrameLayout mContentContainer = findViewById(R.id.notification_action_list_margin_target); mExpandButtonAndContentContainer = findViewById(R.id.expand_button_and_content_container); mExpandButton = findViewById(R.id.expand_button); mTopLine = findViewById(R.id.notification_top_line); mMessageSpacingStandard = getResources().getDimensionPixelSize( R.dimen.notification_messaging_spacing); mMessageSpacingGroup = getResources().getDimensionPixelSize( Loading Loading @@ -753,7 +757,7 @@ public class ConversationLayout extends FrameLayout mImageMessageContainer.addView(newMessage); } } mImageMessageContainer.setVisibility(newMessage != null ? VISIBLE : GONE); mImageMessageContainer.setVisibility(isShowingImage ? VISIBLE : GONE); if (mRightIconView != null && mRightIconView.getDrawable() != null) { // When showing an image message, do not show the large icon. Removing the drawable Loading @@ -763,23 +767,70 @@ public class ConversationLayout extends FrameLayout mRightIconView.setVisibility(GONE); } } else { // Only alter the padding if we're not showing the large icon; otherwise it's already // Only alter the spacing if we're not showing the large icon; otherwise it's already // been adjusted in Notification.java and we shouldn't override it. adjustExpandButtonPadding(isShowingImage); adjustSpacingForImage(); } } /** * When showing an isolated image message similar to the large icon, adjust the padding of the * expand button in the same way we do for large icons. * When showing an isolated image message similar to the large icon, adjust the margin of the * text in the same way we do for large icons, to leave space for the image. */ private void adjustExpandButtonPadding(boolean isShowingImage) { if (notificationsRedesignTemplates() && mExpandButton != null) { final Resources res = mContext.getResources(); int normalPadding = res.getDimensionPixelSize(R.dimen.notification_2025_margin); int iconSpacing = res.getDimensionPixelSize( R.dimen.notification_2025_expand_button_right_icon_spacing); mExpandButton.setStartPadding(isShowingImage ? iconSpacing : normalPadding); private void adjustSpacingForImage() { if (notificationsRedesignTemplates()) { int spacingForExpander = getSpacingForExpander(); updateMarginEnd(mImageMessageContainer, spacingForExpander); int spacingForImage = getSpacingForImage(); int textMargin = spacingForImage + spacingForExpander; updateMarginEnd(mTopLine, textMargin); // Only apply spacing to second line if there's an image - otherwise the text should // flow under the expander. if (spacingForImage > 0) { updateMarginEnd(mMessagingLinearLayout, textMargin); } } } /** * Calculate the amount of space necessary for the expander (adjusted with the font size). */ private int getSpacingForExpander() { int iconMarginEnd = getResources().getDimensionPixelSize( R.dimen.notification_2025_right_icon_margin_end); int extraSpaceForExpander = getResources().getDimensionPixelSize( R.dimen.notification_2025_extra_space_for_expander); return iconMarginEnd + extraSpaceForExpander; } /** * Calculate the amount of space necessary for the image if present. */ private int getSpacingForImage() { if (mImageMessageContainer != null && mImageMessageContainer.getVisibility() == VISIBLE) { // Unlike large icons which can be wider than tall, isolated image messages can only // be square, so we can use the fixed width directly. int imageWidth = getResources().getDimensionPixelSize( R.dimen.notification_right_icon_size); int iconMarginStart = getResources().getDimensionPixelSize( R.dimen.notification_2025_right_icon_content_margin); return iconMarginStart + imageWidth; } return 0; } private void updateMarginEnd(ViewGroup view, int marginEnd) { if (view == null) { Log.wtf(TAG, "The view passed to updateMarginEnd should not be null"); return; } MarginLayoutParams lp = (MarginLayoutParams) view.getLayoutParams(); if (lp.getMarginEnd() != marginEnd) { lp.setMarginEnd(marginEnd); view.setLayoutParams(lp); } } Loading core/java/com/android/internal/widget/MessagingLayout.java +71 −18 Original line number Diff line number Diff line Loading @@ -29,7 +29,6 @@ import android.app.Notification; import android.app.Person; import android.app.RemoteInputHistoryItem; import android.content.Context; import android.content.res.Resources; import android.graphics.Rect; import android.graphics.drawable.Icon; import android.os.Bundle; Loading @@ -38,6 +37,8 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.view.NotificationTopLineView; import android.view.RemotableViewMethod; import android.view.View; import android.view.ViewGroup; Loading Loading @@ -66,6 +67,7 @@ public class MessagingLayout extends FrameLayout public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f); public static final Interpolator FAST_OUT_LINEAR_IN = new PathInterpolator(0.4f, 0f, 1f, 1f); public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f); private static final String TAG = "MessagingLayout"; private static final int MAX_SUMMARIZATION_LINES = 3; public static final OnLayoutChangeListener MESSAGING_PROPERTY_ANIMATOR = new MessagingPropertyAnimator(); Loading @@ -77,7 +79,7 @@ public class MessagingLayout extends FrameLayout private final ArrayList<MessagingGroup> mGroups = new ArrayList<>(); private MessagingLinearLayout mImageMessageContainer; private ImageView mRightIconView; private NotificationExpandButton mExpandButton; private NotificationTopLineView mTopLine; private Rect mMessagingClipRect; private int mLayoutColor; private int mSenderTextColor; Loading Loading @@ -119,7 +121,7 @@ public class MessagingLayout extends FrameLayout mMessagingLinearLayout = findViewById(R.id.notification_messaging); mImageMessageContainer = findViewById(R.id.conversation_image_message_container); mRightIconView = findViewById(R.id.right_icon); mExpandButton = findViewById(R.id.expand_button); mTopLine = findViewById(R.id.notification_top_line); if (notificationsRedesignTemplates()) { // The left_icon in the header has the default rounded square background. Make sure // we're using the circular background instead. Loading Loading @@ -211,6 +213,7 @@ public class MessagingLayout extends FrameLayout /** * Set Messaging data * * @param extras Bundle contains messaging data */ @RemotableViewMethod(asyncImpl = "setDataAsync") Loading Loading @@ -267,6 +270,7 @@ public class MessagingLayout extends FrameLayout * RemotableViewMethod's asyncImpl of {@link #setData(Bundle)}. * This should be called on a background thread, and returns a Runnable which is then must be * called on the main thread to complete the operation and set text. * * @param extras Bundle contains messaging data * @hide */ Loading @@ -288,6 +292,7 @@ public class MessagingLayout extends FrameLayout /** * enable/disable precomputed text usage * * @hide */ public void setPrecomputedTextEnabled(boolean precomputedTextEnabled) { Loading Loading @@ -381,23 +386,70 @@ public class MessagingLayout extends FrameLayout mRightIconView.setVisibility(GONE); } } else { // Only alter the padding if we're not showing the large icon; otherwise it's already // Only alter the spacing if we're not showing the large icon; otherwise it's already // been adjusted in Notification.java and we shouldn't override it. adjustExpandButtonPadding(isShowingImage); adjustSpacingForImage(); } } /** * When showing an isolated image message similar to the large icon, adjust the margin of the * text in the same way we do for large icons, to leave space for the image. */ private void adjustSpacingForImage() { if (notificationsRedesignTemplates()) { int spacingForExpander = getSpacingForExpander(); updateMarginEnd(mImageMessageContainer, spacingForExpander); int spacingForImage = getSpacingForImage(); int textMargin = spacingForImage + spacingForExpander; updateMarginEnd(mTopLine, textMargin); // Only apply spacing to second line if there's an image - otherwise the text should // flow under the expander. if (spacingForImage > 0) { updateMarginEnd(mMessagingLinearLayout, textMargin); } } } /** * Calculate the amount of space necessary for the expander (adjusted with the font size). */ private int getSpacingForExpander() { int iconMarginEnd = getResources().getDimensionPixelSize( R.dimen.notification_2025_right_icon_margin_end); int extraSpaceForExpander = getResources().getDimensionPixelSize( R.dimen.notification_2025_extra_space_for_expander); return iconMarginEnd + extraSpaceForExpander; } /** * When showing an isolated image message similar to the large icon, adjust the padding of the * expand button in the same way we do for large icons. * Calculate the amount of space necessary for the image if present. */ private void adjustExpandButtonPadding(boolean isShowingImage) { if (notificationsRedesignTemplates() && mExpandButton != null) { final Resources res = mContext.getResources(); int normalPadding = res.getDimensionPixelSize(R.dimen.notification_2025_margin); int iconSpacing = res.getDimensionPixelSize( R.dimen.notification_2025_expand_button_right_icon_spacing); mExpandButton.setStartPadding(isShowingImage ? iconSpacing : normalPadding); private int getSpacingForImage() { if (mImageMessageContainer != null && mImageMessageContainer.getVisibility() == VISIBLE) { // Unlike large icons which can be wider than tall, isolated image messages can only // be square, so we can use the fixed width directly. int imageWidth = getResources().getDimensionPixelSize( R.dimen.notification_right_icon_size); int iconMarginStart = getResources().getDimensionPixelSize( R.dimen.notification_2025_right_icon_content_margin); return iconMarginStart + imageWidth; } return 0; } private void updateMarginEnd(ViewGroup view, int marginEnd) { if (view == null) { Log.wtf(TAG, "The view passed to updateMarginEnd should not be null"); return; } MarginLayoutParams lp = (MarginLayoutParams) view.getLayoutParams(); if (lp.getMarginEnd() != marginEnd) { lp.setMarginEnd(marginEnd); view.setLayoutParams(lp); } } Loading Loading @@ -525,6 +577,7 @@ public class MessagingLayout extends FrameLayout mSenderTextColor = color; return () -> {}; } /** * @param color the color of the notification background */ Loading core/res/res/layout/notification_2025_right_icon.xml +2 −2 Original line number Diff line number Diff line Loading @@ -13,14 +13,14 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License --> <!-- Large icon to be used in expanded notification layouts. --> <!-- Large icon to be used in notification layouts. --> <com.android.internal.widget.CachingIconView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/right_icon" android:layout_width="@dimen/notification_right_icon_size" android:layout_height="@dimen/notification_right_icon_size" android:layout_gravity="top|end" android:layout_marginEnd="@dimen/notification_2025_right_icon_expanded_margin_end" android:layout_marginEnd="@dimen/notification_2025_right_icon_margin_end" android:layout_marginTop="@dimen/notification_2025_right_icon_vertical_margin" android:background="@drawable/notification_large_icon_outline" android:clipToOutline="true" Loading core/res/res/layout/notification_2025_template_collapsed_base.xml +9 −20 Original line number Diff line number Diff line Loading @@ -58,12 +58,11 @@ android:focusable="false" /> <LinearLayout <FrameLayout android:id="@+id/notification_headerless_view_row" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginStart="@dimen/notification_2025_content_margin_start" android:orientation="horizontal" > <!-- Loading @@ -72,19 +71,19 @@ --> <LinearLayout android:id="@+id/notification_headerless_view_column" android:layout_width="0px" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_weight="1" android:layout_marginVertical="@dimen/notification_2025_reduced_margin" android:orientation="vertical" > <NotificationTopLineView android:id="@+id/notification_top_line" android:layout_width="wrap_content" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="@dimen/notification_2025_additional_margin" android:layout_marginEnd="@dimen/notification_2025_content_margin_end" android:minHeight="@dimen/notification_2025_content_min_height" android:clipChildren="false" android:theme="@style/Theme.DeviceDefault.Notification" Loading Loading @@ -123,6 +122,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/notification_2025_additional_margin" android:layout_marginEnd="@dimen/notification_2025_margin" android:minHeight="@dimen/notification_headerless_line_height" > <include layout="@layout/notification_2025_text" /> Loading @@ -132,32 +132,21 @@ layout="@layout/notification_template_progress" android:layout_width="match_parent" android:layout_height="@dimen/notification_headerless_line_height" android:layout_marginEnd="@dimen/notification_2025_margin" /> </LinearLayout> </LinearLayout> <com.android.internal.widget.CachingIconView android:id="@+id/right_icon" android:layout_width="@dimen/notification_right_icon_size" android:layout_height="@dimen/notification_right_icon_size" android:layout_gravity="center_vertical|end" android:layout_marginVertical="@dimen/notification_2025_right_icon_vertical_margin" android:layout_marginStart="@dimen/notification_2025_right_icon_content_margin" android:background="@drawable/notification_large_icon_outline" android:clipToOutline="true" android:importantForAccessibility="no" android:scaleType="centerCrop" android:maxDrawableWidth="@dimen/notification_right_icon_size" android:maxDrawableHeight="@dimen/notification_right_icon_size" /> <include layout="@layout/notification_2025_right_icon" /> <FrameLayout android:id="@+id/expand_button_touch_container" android:layout_width="wrap_content" android:layout_height="match_parent" android:minWidth="@dimen/notification_2025_margin" android:layout_gravity="top|end" > <include layout="@layout/notification_2025_expand_button" Loading @@ -168,7 +157,7 @@ </FrameLayout> </LinearLayout> </FrameLayout> <include layout="@layout/notification_close_button" android:id="@+id/close_button" Loading Loading
core/java/android/app/Notification.java +23 −4 Original line number Diff line number Diff line Loading @@ -6321,6 +6321,13 @@ public class Notification implements Parcelable // If there is no title, the text (or big_text) needs to wrap around the image result.mTitleMarginSet.applyToView(contentView, p.mTextViewId); contentView.setInt(p.mTextViewId, "setNumIndentLines", p.hasTitle() ? 0 : 1); } else if (notificationsRedesignTemplates() && !p.mCompact) { // In the collapsed view (except for compact HUNs), the top line needs to // accommodate both the expander and large icon (when present) result.mHeadingFullMarginSet.applyToView(contentView, R.id.notification_top_line); // The text underneath can flow below the expander, but only if there's no large // icon to leave space for (similar to the title in the expanded version). result.mTitleMarginSet.applyToView(contentView, R.id.notification_main_column); } // The expand button uses paddings rather than margins, so we'll adjust it // separately. Loading Loading @@ -6435,7 +6442,7 @@ public class Notification implements Parcelable contentView.setImageViewIcon(R.id.right_icon, rightIcon); contentView.setIntTag(R.id.right_icon, R.id.tag_keep_when_showing_left_icon, isPromotedPicture ? 1 : 0); if ((notificationsRedesignTemplates() || Flags.uiRichOngoing()) && !p.mHeaderless) { if (notificationsRedesignTemplates() || Flags.uiRichOngoing()) { contentView.setViewLayoutMargin(R.id.right_icon, RemoteViews.MARGIN_END, getLargeIconMarginEnd(p), COMPLEX_UNIT_PX); } Loading Loading @@ -6464,7 +6471,7 @@ public class Notification implements Parcelable if (notificationsRedesignTemplates()) { int rightIconMarginPx = res.getDimensionPixelSize( R.dimen.notification_2025_right_icon_expanded_margin_end); R.dimen.notification_2025_right_icon_margin_end); int extraSpaceForExpanderPx = res.getDimensionPixelSize( R.dimen.notification_2025_extra_space_for_expander); return rightIconMarginPx + extraSpaceForExpanderPx; Loading Loading @@ -7172,6 +7179,7 @@ public class Notification implements Parcelable final StandardTemplateParams p = mParams.reset() .viewType(StandardTemplateParams.VIEW_TYPE_HEADS_UP) .compact(true) .fillTextsFrom(this); // Notification text is shown as secondary header text // for the minimal hun when it is provided. Loading Loading @@ -8435,8 +8443,12 @@ public class Notification implements Parcelable // ensures that we don't under-pad the content, which could lead to abuse, at the // cost of making single-line custom content over-padded. Builder.setHeaderlessVerticalMargins(template, p, true /* hasSecondLine */); } else { if (notificationsRedesignTemplates()) { // also update the end margin to account for the large icon or expander result.mHeadingFullMarginSet.applyToView(template, R.id.notification_main_column); } } else { Resources resources = context.getResources(); result.mTitleMarginSet.applyToView(template, R.id.notification_main_column, resources.getDimension(R.dimen.notification_content_margin_end) Loading Loading @@ -16505,6 +16517,7 @@ public class Notification implements Parcelable int mViewType = VIEW_TYPE_UNSPECIFIED; boolean mHeaderless; boolean mCompact; boolean mHideAppName; boolean mHideTitle; boolean mHideSubText; Loading @@ -16530,6 +16543,7 @@ public class Notification implements Parcelable final StandardTemplateParams reset() { mViewType = VIEW_TYPE_UNSPECIFIED; mHeaderless = false; mCompact = false; mHideAppName = false; mHideTitle = false; mHideSubText = false; Loading Loading @@ -16568,6 +16582,11 @@ public class Notification implements Parcelable return this; } public StandardTemplateParams compact(boolean compact) { mCompact = compact; return this; } public StandardTemplateParams hideAppName(boolean hideAppName) { mHideAppName = hideAppName; return this;
core/java/com/android/internal/widget/ConversationLayout.java +65 −14 Original line number Diff line number Diff line Loading @@ -34,7 +34,6 @@ import android.app.Person; import android.app.RemoteInputHistoryItem; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Resources; import android.graphics.Rect; import android.graphics.Typeface; import android.graphics.drawable.Drawable; Loading @@ -49,8 +48,10 @@ import android.text.style.StyleSpan; import android.util.ArrayMap; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.view.Gravity; import android.view.MotionEvent; import android.view.NotificationTopLineView; import android.view.RemotableViewMethod; import android.view.TouchDelegate; import android.view.View; Loading Loading @@ -86,6 +87,7 @@ public class ConversationLayout extends FrameLayout public static final Interpolator FAST_OUT_LINEAR_IN = new PathInterpolator(0.4f, 0f, 1f, 1f); public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f); public static final Interpolator OVERSHOOT = new PathInterpolator(0.4f, 0f, 0.2f, 1.4f); private static final String TAG = "ConversationLayout"; private static final int MAX_SUMMARIZATION_LINES = 3; public static final int IMPORTANCE_ANIM_GROW_DURATION = 250; public static final int IMPORTANCE_ANIM_SHRINK_DURATION = 200; Loading Loading @@ -123,6 +125,7 @@ public class ConversationLayout extends FrameLayout private ViewGroup mExpandButtonAndContentContainer; private ViewGroup mExpandButtonContainerA11yContainer; private NotificationExpandButton mExpandButton; private NotificationTopLineView mTopLine; private MessagingLinearLayout mImageMessageContainer; private ImageView mRightIconView; private int mBadgeProtrusion; Loading Loading @@ -271,6 +274,7 @@ public class ConversationLayout extends FrameLayout mContentContainer = findViewById(R.id.notification_action_list_margin_target); mExpandButtonAndContentContainer = findViewById(R.id.expand_button_and_content_container); mExpandButton = findViewById(R.id.expand_button); mTopLine = findViewById(R.id.notification_top_line); mMessageSpacingStandard = getResources().getDimensionPixelSize( R.dimen.notification_messaging_spacing); mMessageSpacingGroup = getResources().getDimensionPixelSize( Loading Loading @@ -753,7 +757,7 @@ public class ConversationLayout extends FrameLayout mImageMessageContainer.addView(newMessage); } } mImageMessageContainer.setVisibility(newMessage != null ? VISIBLE : GONE); mImageMessageContainer.setVisibility(isShowingImage ? VISIBLE : GONE); if (mRightIconView != null && mRightIconView.getDrawable() != null) { // When showing an image message, do not show the large icon. Removing the drawable Loading @@ -763,23 +767,70 @@ public class ConversationLayout extends FrameLayout mRightIconView.setVisibility(GONE); } } else { // Only alter the padding if we're not showing the large icon; otherwise it's already // Only alter the spacing if we're not showing the large icon; otherwise it's already // been adjusted in Notification.java and we shouldn't override it. adjustExpandButtonPadding(isShowingImage); adjustSpacingForImage(); } } /** * When showing an isolated image message similar to the large icon, adjust the padding of the * expand button in the same way we do for large icons. * When showing an isolated image message similar to the large icon, adjust the margin of the * text in the same way we do for large icons, to leave space for the image. */ private void adjustExpandButtonPadding(boolean isShowingImage) { if (notificationsRedesignTemplates() && mExpandButton != null) { final Resources res = mContext.getResources(); int normalPadding = res.getDimensionPixelSize(R.dimen.notification_2025_margin); int iconSpacing = res.getDimensionPixelSize( R.dimen.notification_2025_expand_button_right_icon_spacing); mExpandButton.setStartPadding(isShowingImage ? iconSpacing : normalPadding); private void adjustSpacingForImage() { if (notificationsRedesignTemplates()) { int spacingForExpander = getSpacingForExpander(); updateMarginEnd(mImageMessageContainer, spacingForExpander); int spacingForImage = getSpacingForImage(); int textMargin = spacingForImage + spacingForExpander; updateMarginEnd(mTopLine, textMargin); // Only apply spacing to second line if there's an image - otherwise the text should // flow under the expander. if (spacingForImage > 0) { updateMarginEnd(mMessagingLinearLayout, textMargin); } } } /** * Calculate the amount of space necessary for the expander (adjusted with the font size). */ private int getSpacingForExpander() { int iconMarginEnd = getResources().getDimensionPixelSize( R.dimen.notification_2025_right_icon_margin_end); int extraSpaceForExpander = getResources().getDimensionPixelSize( R.dimen.notification_2025_extra_space_for_expander); return iconMarginEnd + extraSpaceForExpander; } /** * Calculate the amount of space necessary for the image if present. */ private int getSpacingForImage() { if (mImageMessageContainer != null && mImageMessageContainer.getVisibility() == VISIBLE) { // Unlike large icons which can be wider than tall, isolated image messages can only // be square, so we can use the fixed width directly. int imageWidth = getResources().getDimensionPixelSize( R.dimen.notification_right_icon_size); int iconMarginStart = getResources().getDimensionPixelSize( R.dimen.notification_2025_right_icon_content_margin); return iconMarginStart + imageWidth; } return 0; } private void updateMarginEnd(ViewGroup view, int marginEnd) { if (view == null) { Log.wtf(TAG, "The view passed to updateMarginEnd should not be null"); return; } MarginLayoutParams lp = (MarginLayoutParams) view.getLayoutParams(); if (lp.getMarginEnd() != marginEnd) { lp.setMarginEnd(marginEnd); view.setLayoutParams(lp); } } Loading
core/java/com/android/internal/widget/MessagingLayout.java +71 −18 Original line number Diff line number Diff line Loading @@ -29,7 +29,6 @@ import android.app.Notification; import android.app.Person; import android.app.RemoteInputHistoryItem; import android.content.Context; import android.content.res.Resources; import android.graphics.Rect; import android.graphics.drawable.Icon; import android.os.Bundle; Loading @@ -38,6 +37,8 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.view.NotificationTopLineView; import android.view.RemotableViewMethod; import android.view.View; import android.view.ViewGroup; Loading Loading @@ -66,6 +67,7 @@ public class MessagingLayout extends FrameLayout public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f); public static final Interpolator FAST_OUT_LINEAR_IN = new PathInterpolator(0.4f, 0f, 1f, 1f); public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f); private static final String TAG = "MessagingLayout"; private static final int MAX_SUMMARIZATION_LINES = 3; public static final OnLayoutChangeListener MESSAGING_PROPERTY_ANIMATOR = new MessagingPropertyAnimator(); Loading @@ -77,7 +79,7 @@ public class MessagingLayout extends FrameLayout private final ArrayList<MessagingGroup> mGroups = new ArrayList<>(); private MessagingLinearLayout mImageMessageContainer; private ImageView mRightIconView; private NotificationExpandButton mExpandButton; private NotificationTopLineView mTopLine; private Rect mMessagingClipRect; private int mLayoutColor; private int mSenderTextColor; Loading Loading @@ -119,7 +121,7 @@ public class MessagingLayout extends FrameLayout mMessagingLinearLayout = findViewById(R.id.notification_messaging); mImageMessageContainer = findViewById(R.id.conversation_image_message_container); mRightIconView = findViewById(R.id.right_icon); mExpandButton = findViewById(R.id.expand_button); mTopLine = findViewById(R.id.notification_top_line); if (notificationsRedesignTemplates()) { // The left_icon in the header has the default rounded square background. Make sure // we're using the circular background instead. Loading Loading @@ -211,6 +213,7 @@ public class MessagingLayout extends FrameLayout /** * Set Messaging data * * @param extras Bundle contains messaging data */ @RemotableViewMethod(asyncImpl = "setDataAsync") Loading Loading @@ -267,6 +270,7 @@ public class MessagingLayout extends FrameLayout * RemotableViewMethod's asyncImpl of {@link #setData(Bundle)}. * This should be called on a background thread, and returns a Runnable which is then must be * called on the main thread to complete the operation and set text. * * @param extras Bundle contains messaging data * @hide */ Loading @@ -288,6 +292,7 @@ public class MessagingLayout extends FrameLayout /** * enable/disable precomputed text usage * * @hide */ public void setPrecomputedTextEnabled(boolean precomputedTextEnabled) { Loading Loading @@ -381,23 +386,70 @@ public class MessagingLayout extends FrameLayout mRightIconView.setVisibility(GONE); } } else { // Only alter the padding if we're not showing the large icon; otherwise it's already // Only alter the spacing if we're not showing the large icon; otherwise it's already // been adjusted in Notification.java and we shouldn't override it. adjustExpandButtonPadding(isShowingImage); adjustSpacingForImage(); } } /** * When showing an isolated image message similar to the large icon, adjust the margin of the * text in the same way we do for large icons, to leave space for the image. */ private void adjustSpacingForImage() { if (notificationsRedesignTemplates()) { int spacingForExpander = getSpacingForExpander(); updateMarginEnd(mImageMessageContainer, spacingForExpander); int spacingForImage = getSpacingForImage(); int textMargin = spacingForImage + spacingForExpander; updateMarginEnd(mTopLine, textMargin); // Only apply spacing to second line if there's an image - otherwise the text should // flow under the expander. if (spacingForImage > 0) { updateMarginEnd(mMessagingLinearLayout, textMargin); } } } /** * Calculate the amount of space necessary for the expander (adjusted with the font size). */ private int getSpacingForExpander() { int iconMarginEnd = getResources().getDimensionPixelSize( R.dimen.notification_2025_right_icon_margin_end); int extraSpaceForExpander = getResources().getDimensionPixelSize( R.dimen.notification_2025_extra_space_for_expander); return iconMarginEnd + extraSpaceForExpander; } /** * When showing an isolated image message similar to the large icon, adjust the padding of the * expand button in the same way we do for large icons. * Calculate the amount of space necessary for the image if present. */ private void adjustExpandButtonPadding(boolean isShowingImage) { if (notificationsRedesignTemplates() && mExpandButton != null) { final Resources res = mContext.getResources(); int normalPadding = res.getDimensionPixelSize(R.dimen.notification_2025_margin); int iconSpacing = res.getDimensionPixelSize( R.dimen.notification_2025_expand_button_right_icon_spacing); mExpandButton.setStartPadding(isShowingImage ? iconSpacing : normalPadding); private int getSpacingForImage() { if (mImageMessageContainer != null && mImageMessageContainer.getVisibility() == VISIBLE) { // Unlike large icons which can be wider than tall, isolated image messages can only // be square, so we can use the fixed width directly. int imageWidth = getResources().getDimensionPixelSize( R.dimen.notification_right_icon_size); int iconMarginStart = getResources().getDimensionPixelSize( R.dimen.notification_2025_right_icon_content_margin); return iconMarginStart + imageWidth; } return 0; } private void updateMarginEnd(ViewGroup view, int marginEnd) { if (view == null) { Log.wtf(TAG, "The view passed to updateMarginEnd should not be null"); return; } MarginLayoutParams lp = (MarginLayoutParams) view.getLayoutParams(); if (lp.getMarginEnd() != marginEnd) { lp.setMarginEnd(marginEnd); view.setLayoutParams(lp); } } Loading Loading @@ -525,6 +577,7 @@ public class MessagingLayout extends FrameLayout mSenderTextColor = color; return () -> {}; } /** * @param color the color of the notification background */ Loading
core/res/res/layout/notification_2025_right_icon.xml +2 −2 Original line number Diff line number Diff line Loading @@ -13,14 +13,14 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License --> <!-- Large icon to be used in expanded notification layouts. --> <!-- Large icon to be used in notification layouts. --> <com.android.internal.widget.CachingIconView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/right_icon" android:layout_width="@dimen/notification_right_icon_size" android:layout_height="@dimen/notification_right_icon_size" android:layout_gravity="top|end" android:layout_marginEnd="@dimen/notification_2025_right_icon_expanded_margin_end" android:layout_marginEnd="@dimen/notification_2025_right_icon_margin_end" android:layout_marginTop="@dimen/notification_2025_right_icon_vertical_margin" android:background="@drawable/notification_large_icon_outline" android:clipToOutline="true" Loading
core/res/res/layout/notification_2025_template_collapsed_base.xml +9 −20 Original line number Diff line number Diff line Loading @@ -58,12 +58,11 @@ android:focusable="false" /> <LinearLayout <FrameLayout android:id="@+id/notification_headerless_view_row" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginStart="@dimen/notification_2025_content_margin_start" android:orientation="horizontal" > <!-- Loading @@ -72,19 +71,19 @@ --> <LinearLayout android:id="@+id/notification_headerless_view_column" android:layout_width="0px" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_weight="1" android:layout_marginVertical="@dimen/notification_2025_reduced_margin" android:orientation="vertical" > <NotificationTopLineView android:id="@+id/notification_top_line" android:layout_width="wrap_content" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="@dimen/notification_2025_additional_margin" android:layout_marginEnd="@dimen/notification_2025_content_margin_end" android:minHeight="@dimen/notification_2025_content_min_height" android:clipChildren="false" android:theme="@style/Theme.DeviceDefault.Notification" Loading Loading @@ -123,6 +122,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/notification_2025_additional_margin" android:layout_marginEnd="@dimen/notification_2025_margin" android:minHeight="@dimen/notification_headerless_line_height" > <include layout="@layout/notification_2025_text" /> Loading @@ -132,32 +132,21 @@ layout="@layout/notification_template_progress" android:layout_width="match_parent" android:layout_height="@dimen/notification_headerless_line_height" android:layout_marginEnd="@dimen/notification_2025_margin" /> </LinearLayout> </LinearLayout> <com.android.internal.widget.CachingIconView android:id="@+id/right_icon" android:layout_width="@dimen/notification_right_icon_size" android:layout_height="@dimen/notification_right_icon_size" android:layout_gravity="center_vertical|end" android:layout_marginVertical="@dimen/notification_2025_right_icon_vertical_margin" android:layout_marginStart="@dimen/notification_2025_right_icon_content_margin" android:background="@drawable/notification_large_icon_outline" android:clipToOutline="true" android:importantForAccessibility="no" android:scaleType="centerCrop" android:maxDrawableWidth="@dimen/notification_right_icon_size" android:maxDrawableHeight="@dimen/notification_right_icon_size" /> <include layout="@layout/notification_2025_right_icon" /> <FrameLayout android:id="@+id/expand_button_touch_container" android:layout_width="wrap_content" android:layout_height="match_parent" android:minWidth="@dimen/notification_2025_margin" android:layout_gravity="top|end" > <include layout="@layout/notification_2025_expand_button" Loading @@ -168,7 +157,7 @@ </FrameLayout> </LinearLayout> </FrameLayout> <include layout="@layout/notification_close_button" android:id="@+id/close_button" Loading