Loading core/java/com/android/internal/widget/ConversationLayout.java +75 −20 Original line number Diff line number Diff line Loading @@ -35,10 +35,14 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.Typeface; import android.graphics.drawable.Icon; import android.os.Bundle; import android.os.Parcelable; import android.text.Spannable; import android.text.SpannableString; import android.text.TextUtils; import android.text.style.StyleSpan; import android.util.ArrayMap; import android.util.AttributeSet; import android.util.DisplayMetrics; Loading Loading @@ -109,7 +113,7 @@ public class ConversationLayout extends FrameLayout private CharSequence mNameReplacement; private boolean mIsCollapsed; private ImageResolver mImageResolver; private CachingIconView mConversationIcon; private CachingIconView mConversationIconView; private View mConversationIconContainer; private int mConversationIconTopPadding; private int mConversationIconTopPaddingExpandedGroup; Loading Loading @@ -157,6 +161,7 @@ public class ConversationLayout extends FrameLayout private ViewGroup mAppOps; private Rect mAppOpsTouchRect = new Rect(); private float mMinTouchSize; private Icon mConversationIcon; public ConversationLayout(@NonNull Context context) { super(context); Loading Loading @@ -192,7 +197,7 @@ public class ConversationLayout extends FrameLayout mAvatarSize = getResources().getDimensionPixelSize(R.dimen.messaging_avatar_size); mTextPaint.setTextAlign(Paint.Align.CENTER); mTextPaint.setAntiAlias(true); mConversationIcon = findViewById(R.id.conversation_icon); mConversationIconView = findViewById(R.id.conversation_icon); mConversationIconContainer = findViewById(R.id.conversation_icon_container); mIcon = findViewById(R.id.icon); mAppOps = findViewById(com.android.internal.R.id.app_ops); Loading Loading @@ -232,7 +237,7 @@ public class ConversationLayout extends FrameLayout }); // When the conversation icon is gone, hide the whole badge mConversationIcon.setOnForceHiddenChangedListener((forceHidden) -> { mConversationIconView.setOnForceHiddenChangedListener((forceHidden) -> { animateViewForceHidden(mConversationIconBadgeBg, forceHidden); animateViewForceHidden(mImportanceRingView, forceHidden); animateViewForceHidden(mIcon, forceHidden); Loading Loading @@ -463,7 +468,7 @@ public class ConversationLayout extends FrameLayout CharSequence conversationText = mConversationTitle; if (mIsOneToOne) { // Let's resolve the icon / text from the last sender mConversationIcon.setVisibility(VISIBLE); mConversationIconView.setVisibility(VISIBLE); mConversationFacePile.setVisibility(GONE); CharSequence userKey = getKey(mUser); for (int i = mGroups.size() - 1; i >= 0; i--) { Loading @@ -480,17 +485,20 @@ public class ConversationLayout extends FrameLayout if (avatarIcon == null) { avatarIcon = createAvatarSymbol(conversationText, "", mLayoutColor); } mConversationIcon.setImageIcon(avatarIcon); mConversationIcon = avatarIcon; mConversationIconView.setImageIcon(mConversationIcon); break; } } } else { if (mLargeIcon != null) { mConversationIcon.setVisibility(VISIBLE); mConversationIcon = mLargeIcon; mConversationIconView.setVisibility(VISIBLE); mConversationFacePile.setVisibility(GONE); mConversationIcon.setImageIcon(mLargeIcon); mConversationIconView.setImageIcon(mLargeIcon); } else { mConversationIcon.setVisibility(GONE); mConversationIcon = null; mConversationIconView.setVisibility(GONE); // This will also inflate it! mConversationFacePile.setVisibility(VISIBLE); // rebind the value to the inflated view instead of the stub Loading Loading @@ -561,15 +569,8 @@ public class ConversationLayout extends FrameLayout mImageMessageContainer.setVisibility(newMessage != null ? VISIBLE : GONE); } private void bindFacePile() { // Let's bind the face pile ImageView bottomBackground = mConversationFacePile.findViewById( R.id.conversation_face_pile_bottom_background); public void bindFacePile(ImageView bottomBackground, ImageView bottomView, ImageView topView) { applyNotificationBackgroundColor(bottomBackground); ImageView bottomView = mConversationFacePile.findViewById( R.id.conversation_face_pile_bottom); ImageView topView = mConversationFacePile.findViewById( R.id.conversation_face_pile_top); // Let's find the two last conversations: Icon secondLastIcon = null; CharSequence lastKey = null; Loading Loading @@ -601,6 +602,17 @@ public class ConversationLayout extends FrameLayout secondLastIcon = createAvatarSymbol("", "", mLayoutColor); } topView.setImageIcon(secondLastIcon); } private void bindFacePile() { ImageView bottomBackground = mConversationFacePile.findViewById( R.id.conversation_face_pile_bottom_background); ImageView bottomView = mConversationFacePile.findViewById( R.id.conversation_face_pile_bottom); ImageView topView = mConversationFacePile.findViewById( R.id.conversation_face_pile_top); bindFacePile(bottomBackground, bottomView, topView); int conversationAvatarSize; int facepileAvatarSize; Loading @@ -614,7 +626,7 @@ public class ConversationLayout extends FrameLayout facepileAvatarSize = mFacePileAvatarSizeExpandedGroup; facePileBackgroundSize = facepileAvatarSize + 2 * mFacePileProtectionWidthExpanded; } LayoutParams layoutParams = (LayoutParams) mConversationIcon.getLayoutParams(); LayoutParams layoutParams = (LayoutParams) mConversationIconView.getLayoutParams(); layoutParams.width = conversationAvatarSize; layoutParams.height = conversationAvatarSize; mConversationFacePile.setLayoutParams(layoutParams); Loading Loading @@ -664,11 +676,11 @@ public class ConversationLayout extends FrameLayout layoutParams.setMarginStart(sidemargin); mConversationIconBadge.setLayoutParams(layoutParams); if (mConversationIcon.getVisibility() == VISIBLE) { layoutParams = (LayoutParams) mConversationIcon.getLayoutParams(); if (mConversationIconView.getVisibility() == VISIBLE) { layoutParams = (LayoutParams) mConversationIconView.getLayoutParams(); layoutParams.width = conversationAvatarSize; layoutParams.height = conversationAvatarSize; mConversationIcon.setLayoutParams(layoutParams); mConversationIconView.setLayoutParams(layoutParams); } } Loading Loading @@ -719,6 +731,10 @@ public class ConversationLayout extends FrameLayout mConversationTitle = conversationTitle; } public CharSequence getConversationTitle() { return mConversationText.getText(); } private void removeGroups(ArrayList<MessagingGroup> oldGroups) { int size = oldGroups.size(); for (int i = 0; i < size; i++) { Loading Loading @@ -1218,4 +1234,43 @@ public class ConversationLayout extends FrameLayout public void setMessagingClippingDisabled(boolean clippingDisabled) { mMessagingLinearLayout.setClipBounds(clippingDisabled ? null : mMessagingClipRect); } @Nullable public CharSequence getConversationSenderName() { if (mGroups.isEmpty()) { return null; } final CharSequence name = mGroups.get(mGroups.size() - 1).getSenderName(); return getResources().getString(R.string.conversation_single_line_name_display, name); } public boolean isOneToOne() { return mIsOneToOne; } @Nullable public CharSequence getConversationText() { if (mMessages.isEmpty()) { return null; } final MessagingMessage messagingMessage = mMessages.get(mMessages.size() - 1); final CharSequence text = messagingMessage.getMessage().getText(); if (text == null && messagingMessage instanceof MessagingImageMessage) { final String unformatted = getResources().getString(R.string.conversation_single_line_image_placeholder); SpannableString spannableString = new SpannableString(unformatted); spannableString.setSpan( new StyleSpan(Typeface.ITALIC), 0, spannableString.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); return spannableString; } return text; } @Nullable public Icon getConversationIcon() { return mConversationIcon; } } core/res/res/layout/notification_template_header.xml +13 −5 Original line number Diff line number Diff line Loading @@ -24,12 +24,20 @@ android:layout_height="@dimen/notification_header_height" android:clipChildren="false" style="?attr/notificationHeaderStyle"> <!-- Wrapper used to expand the width of the "space" containing the icon programmatically --> <FrameLayout android:id="@+id/header_icon_container" android:layout_width="wrap_content" android:layout_height="wrap_content"> <com.android.internal.widget.CachingIconView android:id="@+id/icon" android:layout_width="?attr/notificationHeaderIconSize" android:layout_height="?attr/notificationHeaderIconSize" android:layout_marginEnd="@dimen/notification_header_icon_margin_end" android:layout_gravity="center" /> </FrameLayout> <TextView android:id="@+id/app_name_text" android:layout_width="wrap_content" Loading core/res/res/values/strings.xml +3 −0 Original line number Diff line number Diff line Loading @@ -5455,6 +5455,9 @@ <!-- The way a conversation name is displayed when single line. The text will be displayed to the end of this text with some spacing --> <string name="conversation_single_line_name_display"><xliff:g id="sender_name" example="Sara">%1$s</xliff:g>:</string> <!-- Text used when a conversation is displayed in a single-line when the latest message is an image. [CHAR_LIMIT=NONE] --> <string name="conversation_single_line_image_placeholder">sent an image</string> <!-- Conversation Title fallback if the there is no name provided in a 1:1 conversation [CHAR LIMIT=40]--> <string name="conversation_title_fallback_one_to_one">Conversation</string> Loading core/res/res/values/styles_device_defaults.xml +4 −0 Original line number Diff line number Diff line Loading @@ -296,6 +296,10 @@ easier. <style name="TextAppearance.DeviceDefault.Notification.Info" parent="TextAppearance.Material.Notification.Info"> <item name="fontFamily">@string/config_bodyFontFamily</item> </style> <style name="TextAppearance.DeviceDefault.Notification.Conversation.AppName" parent="@*android:style/TextAppearance.DeviceDefault.Notification.Title"> <item name="android:textSize">16sp</item> </style> <style name="TextAppearance.DeviceDefault.Widget" parent="TextAppearance.Material.Widget"> <item name="fontFamily">@string/config_bodyFontFamily</item> </style> Loading core/res/res/values/symbols.xml +6 −0 Original line number Diff line number Diff line Loading @@ -1598,6 +1598,8 @@ <java-symbol type="style" name="Theme.DeviceDefault.VoiceInteractionSession" /> <java-symbol type="style" name="Pointer" /> <java-symbol type="style" name="LargePointer" /> <java-symbol type="style" name="TextAppearance.DeviceDefault.Notification.Title" /> <java-symbol type="style" name="TextAppearance.DeviceDefault.Notification.Info" /> <java-symbol type="attr" name="mediaRouteButtonStyle" /> <java-symbol type="attr" name="externalRouteEnabledDrawable" /> Loading Loading @@ -3875,7 +3877,10 @@ <java-symbol type="array" name="config_defaultImperceptibleKillingExemptionPkgs" /> <java-symbol type="array" name="config_defaultImperceptibleKillingExemptionProcStates" /> <java-symbol type="id" name="header_icon_container" /> <java-symbol type="attr" name="notificationHeaderTextAppearance" /> <java-symbol type="string" name="conversation_single_line_name_display" /> <java-symbol type="string" name="conversation_single_line_image_placeholder" /> <java-symbol type="string" name="conversation_title_fallback_one_to_one" /> <java-symbol type="string" name="conversation_title_fallback_group_chat" /> <java-symbol type="id" name="conversation_icon" /> Loading Loading @@ -3919,6 +3924,7 @@ <java-symbol type="layout" name="conversation_face_pile_layout" /> <java-symbol type="id" name="conversation_unread_count" /> <java-symbol type="string" name="unread_convo_overflow" /> <java-symbol type="style" name="TextAppearance.DeviceDefault.Notification.Conversation.AppName" /> <!-- Intent resolver and share sheet --> <java-symbol type="string" name="resolver_personal_tab" /> Loading Loading
core/java/com/android/internal/widget/ConversationLayout.java +75 −20 Original line number Diff line number Diff line Loading @@ -35,10 +35,14 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.Typeface; import android.graphics.drawable.Icon; import android.os.Bundle; import android.os.Parcelable; import android.text.Spannable; import android.text.SpannableString; import android.text.TextUtils; import android.text.style.StyleSpan; import android.util.ArrayMap; import android.util.AttributeSet; import android.util.DisplayMetrics; Loading Loading @@ -109,7 +113,7 @@ public class ConversationLayout extends FrameLayout private CharSequence mNameReplacement; private boolean mIsCollapsed; private ImageResolver mImageResolver; private CachingIconView mConversationIcon; private CachingIconView mConversationIconView; private View mConversationIconContainer; private int mConversationIconTopPadding; private int mConversationIconTopPaddingExpandedGroup; Loading Loading @@ -157,6 +161,7 @@ public class ConversationLayout extends FrameLayout private ViewGroup mAppOps; private Rect mAppOpsTouchRect = new Rect(); private float mMinTouchSize; private Icon mConversationIcon; public ConversationLayout(@NonNull Context context) { super(context); Loading Loading @@ -192,7 +197,7 @@ public class ConversationLayout extends FrameLayout mAvatarSize = getResources().getDimensionPixelSize(R.dimen.messaging_avatar_size); mTextPaint.setTextAlign(Paint.Align.CENTER); mTextPaint.setAntiAlias(true); mConversationIcon = findViewById(R.id.conversation_icon); mConversationIconView = findViewById(R.id.conversation_icon); mConversationIconContainer = findViewById(R.id.conversation_icon_container); mIcon = findViewById(R.id.icon); mAppOps = findViewById(com.android.internal.R.id.app_ops); Loading Loading @@ -232,7 +237,7 @@ public class ConversationLayout extends FrameLayout }); // When the conversation icon is gone, hide the whole badge mConversationIcon.setOnForceHiddenChangedListener((forceHidden) -> { mConversationIconView.setOnForceHiddenChangedListener((forceHidden) -> { animateViewForceHidden(mConversationIconBadgeBg, forceHidden); animateViewForceHidden(mImportanceRingView, forceHidden); animateViewForceHidden(mIcon, forceHidden); Loading Loading @@ -463,7 +468,7 @@ public class ConversationLayout extends FrameLayout CharSequence conversationText = mConversationTitle; if (mIsOneToOne) { // Let's resolve the icon / text from the last sender mConversationIcon.setVisibility(VISIBLE); mConversationIconView.setVisibility(VISIBLE); mConversationFacePile.setVisibility(GONE); CharSequence userKey = getKey(mUser); for (int i = mGroups.size() - 1; i >= 0; i--) { Loading @@ -480,17 +485,20 @@ public class ConversationLayout extends FrameLayout if (avatarIcon == null) { avatarIcon = createAvatarSymbol(conversationText, "", mLayoutColor); } mConversationIcon.setImageIcon(avatarIcon); mConversationIcon = avatarIcon; mConversationIconView.setImageIcon(mConversationIcon); break; } } } else { if (mLargeIcon != null) { mConversationIcon.setVisibility(VISIBLE); mConversationIcon = mLargeIcon; mConversationIconView.setVisibility(VISIBLE); mConversationFacePile.setVisibility(GONE); mConversationIcon.setImageIcon(mLargeIcon); mConversationIconView.setImageIcon(mLargeIcon); } else { mConversationIcon.setVisibility(GONE); mConversationIcon = null; mConversationIconView.setVisibility(GONE); // This will also inflate it! mConversationFacePile.setVisibility(VISIBLE); // rebind the value to the inflated view instead of the stub Loading Loading @@ -561,15 +569,8 @@ public class ConversationLayout extends FrameLayout mImageMessageContainer.setVisibility(newMessage != null ? VISIBLE : GONE); } private void bindFacePile() { // Let's bind the face pile ImageView bottomBackground = mConversationFacePile.findViewById( R.id.conversation_face_pile_bottom_background); public void bindFacePile(ImageView bottomBackground, ImageView bottomView, ImageView topView) { applyNotificationBackgroundColor(bottomBackground); ImageView bottomView = mConversationFacePile.findViewById( R.id.conversation_face_pile_bottom); ImageView topView = mConversationFacePile.findViewById( R.id.conversation_face_pile_top); // Let's find the two last conversations: Icon secondLastIcon = null; CharSequence lastKey = null; Loading Loading @@ -601,6 +602,17 @@ public class ConversationLayout extends FrameLayout secondLastIcon = createAvatarSymbol("", "", mLayoutColor); } topView.setImageIcon(secondLastIcon); } private void bindFacePile() { ImageView bottomBackground = mConversationFacePile.findViewById( R.id.conversation_face_pile_bottom_background); ImageView bottomView = mConversationFacePile.findViewById( R.id.conversation_face_pile_bottom); ImageView topView = mConversationFacePile.findViewById( R.id.conversation_face_pile_top); bindFacePile(bottomBackground, bottomView, topView); int conversationAvatarSize; int facepileAvatarSize; Loading @@ -614,7 +626,7 @@ public class ConversationLayout extends FrameLayout facepileAvatarSize = mFacePileAvatarSizeExpandedGroup; facePileBackgroundSize = facepileAvatarSize + 2 * mFacePileProtectionWidthExpanded; } LayoutParams layoutParams = (LayoutParams) mConversationIcon.getLayoutParams(); LayoutParams layoutParams = (LayoutParams) mConversationIconView.getLayoutParams(); layoutParams.width = conversationAvatarSize; layoutParams.height = conversationAvatarSize; mConversationFacePile.setLayoutParams(layoutParams); Loading Loading @@ -664,11 +676,11 @@ public class ConversationLayout extends FrameLayout layoutParams.setMarginStart(sidemargin); mConversationIconBadge.setLayoutParams(layoutParams); if (mConversationIcon.getVisibility() == VISIBLE) { layoutParams = (LayoutParams) mConversationIcon.getLayoutParams(); if (mConversationIconView.getVisibility() == VISIBLE) { layoutParams = (LayoutParams) mConversationIconView.getLayoutParams(); layoutParams.width = conversationAvatarSize; layoutParams.height = conversationAvatarSize; mConversationIcon.setLayoutParams(layoutParams); mConversationIconView.setLayoutParams(layoutParams); } } Loading Loading @@ -719,6 +731,10 @@ public class ConversationLayout extends FrameLayout mConversationTitle = conversationTitle; } public CharSequence getConversationTitle() { return mConversationText.getText(); } private void removeGroups(ArrayList<MessagingGroup> oldGroups) { int size = oldGroups.size(); for (int i = 0; i < size; i++) { Loading Loading @@ -1218,4 +1234,43 @@ public class ConversationLayout extends FrameLayout public void setMessagingClippingDisabled(boolean clippingDisabled) { mMessagingLinearLayout.setClipBounds(clippingDisabled ? null : mMessagingClipRect); } @Nullable public CharSequence getConversationSenderName() { if (mGroups.isEmpty()) { return null; } final CharSequence name = mGroups.get(mGroups.size() - 1).getSenderName(); return getResources().getString(R.string.conversation_single_line_name_display, name); } public boolean isOneToOne() { return mIsOneToOne; } @Nullable public CharSequence getConversationText() { if (mMessages.isEmpty()) { return null; } final MessagingMessage messagingMessage = mMessages.get(mMessages.size() - 1); final CharSequence text = messagingMessage.getMessage().getText(); if (text == null && messagingMessage instanceof MessagingImageMessage) { final String unformatted = getResources().getString(R.string.conversation_single_line_image_placeholder); SpannableString spannableString = new SpannableString(unformatted); spannableString.setSpan( new StyleSpan(Typeface.ITALIC), 0, spannableString.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); return spannableString; } return text; } @Nullable public Icon getConversationIcon() { return mConversationIcon; } }
core/res/res/layout/notification_template_header.xml +13 −5 Original line number Diff line number Diff line Loading @@ -24,12 +24,20 @@ android:layout_height="@dimen/notification_header_height" android:clipChildren="false" style="?attr/notificationHeaderStyle"> <!-- Wrapper used to expand the width of the "space" containing the icon programmatically --> <FrameLayout android:id="@+id/header_icon_container" android:layout_width="wrap_content" android:layout_height="wrap_content"> <com.android.internal.widget.CachingIconView android:id="@+id/icon" android:layout_width="?attr/notificationHeaderIconSize" android:layout_height="?attr/notificationHeaderIconSize" android:layout_marginEnd="@dimen/notification_header_icon_margin_end" android:layout_gravity="center" /> </FrameLayout> <TextView android:id="@+id/app_name_text" android:layout_width="wrap_content" Loading
core/res/res/values/strings.xml +3 −0 Original line number Diff line number Diff line Loading @@ -5455,6 +5455,9 @@ <!-- The way a conversation name is displayed when single line. The text will be displayed to the end of this text with some spacing --> <string name="conversation_single_line_name_display"><xliff:g id="sender_name" example="Sara">%1$s</xliff:g>:</string> <!-- Text used when a conversation is displayed in a single-line when the latest message is an image. [CHAR_LIMIT=NONE] --> <string name="conversation_single_line_image_placeholder">sent an image</string> <!-- Conversation Title fallback if the there is no name provided in a 1:1 conversation [CHAR LIMIT=40]--> <string name="conversation_title_fallback_one_to_one">Conversation</string> Loading
core/res/res/values/styles_device_defaults.xml +4 −0 Original line number Diff line number Diff line Loading @@ -296,6 +296,10 @@ easier. <style name="TextAppearance.DeviceDefault.Notification.Info" parent="TextAppearance.Material.Notification.Info"> <item name="fontFamily">@string/config_bodyFontFamily</item> </style> <style name="TextAppearance.DeviceDefault.Notification.Conversation.AppName" parent="@*android:style/TextAppearance.DeviceDefault.Notification.Title"> <item name="android:textSize">16sp</item> </style> <style name="TextAppearance.DeviceDefault.Widget" parent="TextAppearance.Material.Widget"> <item name="fontFamily">@string/config_bodyFontFamily</item> </style> Loading
core/res/res/values/symbols.xml +6 −0 Original line number Diff line number Diff line Loading @@ -1598,6 +1598,8 @@ <java-symbol type="style" name="Theme.DeviceDefault.VoiceInteractionSession" /> <java-symbol type="style" name="Pointer" /> <java-symbol type="style" name="LargePointer" /> <java-symbol type="style" name="TextAppearance.DeviceDefault.Notification.Title" /> <java-symbol type="style" name="TextAppearance.DeviceDefault.Notification.Info" /> <java-symbol type="attr" name="mediaRouteButtonStyle" /> <java-symbol type="attr" name="externalRouteEnabledDrawable" /> Loading Loading @@ -3875,7 +3877,10 @@ <java-symbol type="array" name="config_defaultImperceptibleKillingExemptionPkgs" /> <java-symbol type="array" name="config_defaultImperceptibleKillingExemptionProcStates" /> <java-symbol type="id" name="header_icon_container" /> <java-symbol type="attr" name="notificationHeaderTextAppearance" /> <java-symbol type="string" name="conversation_single_line_name_display" /> <java-symbol type="string" name="conversation_single_line_image_placeholder" /> <java-symbol type="string" name="conversation_title_fallback_one_to_one" /> <java-symbol type="string" name="conversation_title_fallback_group_chat" /> <java-symbol type="id" name="conversation_icon" /> Loading Loading @@ -3919,6 +3924,7 @@ <java-symbol type="layout" name="conversation_face_pile_layout" /> <java-symbol type="id" name="conversation_unread_count" /> <java-symbol type="string" name="unread_convo_overflow" /> <java-symbol type="style" name="TextAppearance.DeviceDefault.Notification.Conversation.AppName" /> <!-- Intent resolver and share sheet --> <java-symbol type="string" name="resolver_personal_tab" /> Loading