Loading core/java/android/app/Notification.java +53 −30 Original line number Diff line number Diff line Loading @@ -5116,6 +5116,7 @@ public class Notification implements Parcelable TemplateBindResult result) { p.headerless(resId == getBaseLayoutResource() || resId == getHeadsUpBaseLayoutResource() || resId == getMessagingLayoutResource() || resId == R.layout.notification_template_material_media); RemoteViews contentView = new BuilderRemoteViews(mContext.getApplicationInfo(), resId); Loading Loading @@ -6641,6 +6642,10 @@ public class Notification implements Parcelable return R.layout.notification_template_material_messaging; } private int getBigMessagingLayoutResource() { return R.layout.notification_template_material_big_messaging; } private int getConversationLayoutResource() { return R.layout.notification_template_material_conversation; } Loading Loading @@ -8151,12 +8156,14 @@ public class Notification implements Parcelable */ @Override public RemoteViews makeContentView(boolean increasedHeight) { // All messaging templates contain the actions ArrayList<Action> originalActions = mBuilder.mActions; try { mBuilder.mActions = new ArrayList<>(); RemoteViews remoteViews = makeMessagingView(true /* isCollapsed */, false /* hideLargeIcon */); return makeMessagingView(StandardTemplateParams.VIEW_TYPE_NORMAL); } finally { mBuilder.mActions = originalActions; return remoteViews; } } /** Loading Loading @@ -8242,18 +8249,24 @@ public class Notification implements Parcelable */ @Override public RemoteViews makeBigContentView() { return makeMessagingView(false /* isCollapsed */, true /* hideLargeIcon */); return makeMessagingView(StandardTemplateParams.VIEW_TYPE_BIG); } /** * Create a messaging layout. * * @param isCollapsed Should this use the collapsed layout * @param hideRightIcons Should the reply affordance be shown at the end of the notification * @param viewType one of StandardTemplateParams.VIEW_TYPE_NORMAL, VIEW_TYPE_BIG, * VIEW_TYPE_HEADS_UP * @return the created remoteView. */ @NonNull private RemoteViews makeMessagingView(boolean isCollapsed, boolean hideRightIcons) { private RemoteViews makeMessagingView(int viewType) { boolean isCollapsed = viewType != StandardTemplateParams.VIEW_TYPE_BIG; boolean hideRightIcons = viewType != StandardTemplateParams.VIEW_TYPE_NORMAL; boolean isConversationLayout = mConversationType != CONVERSATION_TYPE_LEGACY; boolean isImportantConversation = mConversationType == CONVERSATION_TYPE_IMPORTANT; boolean isHeaderless = !isConversationLayout && isCollapsed; CharSequence conversationTitle = !TextUtils.isEmpty(super.mBigContentTitle) ? super.mBigContentTitle : mConversationTitle; Loading @@ -8271,23 +8284,26 @@ public class Notification implements Parcelable } else { isOneToOne = !isGroupConversation(); } boolean isConversationLayout = mConversationType != CONVERSATION_TYPE_LEGACY; boolean isImportantConversation = mConversationType == CONVERSATION_TYPE_IMPORTANT; if (isHeaderless && isOneToOne && TextUtils.isEmpty(conversationTitle)) { conversationTitle = getOtherPersonName(); } Icon largeIcon = mBuilder.mN.mLargeIcon; TemplateBindResult bindResult = new TemplateBindResult(); StandardTemplateParams p = mBuilder.mParams.reset() .viewType(isCollapsed ? StandardTemplateParams.VIEW_TYPE_NORMAL : StandardTemplateParams.VIEW_TYPE_BIG) .viewType(viewType) .highlightExpander(isConversationLayout) .hideProgress(true) .title(conversationTitle) .title(isHeaderless ? conversationTitle : null) .text(null) .hideLargeIcon(hideRightIcons || isOneToOne) .headerTextSecondary(conversationTitle); .headerTextSecondary(isHeaderless ? null : conversationTitle); RemoteViews contentView = mBuilder.applyStandardTemplateWithActions( isConversationLayout ? mBuilder.getConversationLayoutResource() : mBuilder.getMessagingLayoutResource(), : isCollapsed ? mBuilder.getMessagingLayoutResource() : mBuilder.getBigMessagingLayoutResource(), p, bindResult); if (isConversationLayout) { Loading @@ -8296,14 +8312,6 @@ public class Notification implements Parcelable } addExtras(mBuilder.mN.extras); if (!isConversationLayout) { // also update the end margin if there is an image // NOTE: This template doesn't support moving this icon to the left, so we don't // need to fully apply the MarginSet contentView.setViewLayoutMargin(R.id.notification_messaging, RemoteViews.MARGIN_END, bindResult.mHeadingExtraMarginSet.getDpValue(), TypedValue.COMPLEX_UNIT_DIP); } contentView.setInt(R.id.status_bar_latest_event_content, "setLayoutColor", mBuilder.getSmallIconColor(p)); contentView.setInt(R.id.status_bar_latest_event_content, "setSenderTextColor", Loading @@ -8329,6 +8337,10 @@ public class Notification implements Parcelable contentView.setBoolean(R.id.status_bar_latest_event_content, "setIsImportantConversation", isImportantConversation); } if (isHeaderless) { // Collapsed legacy messaging style has a 1-line limit. contentView.setInt(R.id.notification_messaging, "setMaxDisplayedLines", 1); } contentView.setIcon(R.id.status_bar_latest_event_content, "setLargeIcon", largeIcon); contentView.setBundle(R.id.status_bar_latest_event_content, "setData", Loading @@ -8336,6 +8348,22 @@ public class Notification implements Parcelable return contentView; } private CharSequence getKey(Person person) { return person == null ? null : person.getKey() == null ? person.getName() : person.getKey(); } private CharSequence getOtherPersonName() { CharSequence userKey = getKey(mUser); for (int i = mMessages.size() - 1; i >= 0; i--) { Person sender = mMessages.get(i).getSenderPerson(); if (sender != null && !TextUtils.equals(userKey, getKey(sender))) { return sender.getName(); } } return null; } private boolean hasOnlyWhiteSpaceSenders() { for (int i = 0; i < mMessages.size(); i++) { Message m = mMessages.get(i); Loading Loading @@ -8370,12 +8398,7 @@ public class Notification implements Parcelable */ @Override public RemoteViews makeHeadsUpContentView(boolean increasedHeight) { RemoteViews remoteViews = makeMessagingView(true /* isCollapsed */, true /* hideLargeIcon */); if (mConversationType == CONVERSATION_TYPE_LEGACY) { remoteViews.setInt(R.id.notification_messaging, "setMaxDisplayedLines", 1); } return remoteViews; return makeMessagingView(StandardTemplateParams.VIEW_TYPE_HEADS_UP); } public static final class Message { Loading core/java/com/android/internal/widget/ConversationLayout.java +3 −36 Original line number Diff line number Diff line Loading @@ -64,6 +64,7 @@ import com.android.internal.R; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.function.Consumer; Loading Loading @@ -530,13 +531,7 @@ public class ConversationLayout extends FrameLayout mConversationText.setText(conversationText); // Update if the groups can hide the sender if they are first (applies to 1:1 conversations) // This needs to happen after all of the above o update all of the groups for (int i = mGroups.size() - 1; i >= 0; i--) { MessagingGroup messagingGroup = mGroups.get(i); CharSequence messageSender = messagingGroup.getSenderName(); boolean canHide = mIsOneToOne && TextUtils.equals(conversationText, messageSender); messagingGroup.setCanHideSenderIfFirst(canHide); } mPeopleHelper.maybeHideFirstSenderName(mGroups, mIsOneToOne, conversationText); updateAppName(); updateIconPositionAndSize(); updateImageMessages(); Loading Loading @@ -779,35 +774,7 @@ public class ConversationLayout extends FrameLayout private void updateTitleAndNamesDisplay() { // Map of unique names to their prefix ArrayMap<CharSequence, String> uniqueNames = new ArrayMap<>(); // Map of single-character string prefix to the only name which uses it, or null if multiple ArrayMap<String, CharSequence> uniqueCharacters = new ArrayMap<>(); for (int i = 0; i < mGroups.size(); i++) { MessagingGroup group = mGroups.get(i); CharSequence senderName = group.getSenderName(); if (!group.needsGeneratedAvatar() || TextUtils.isEmpty(senderName)) { continue; } if (!uniqueNames.containsKey(senderName)) { String charPrefix = mPeopleHelper.findNamePrefix(senderName, null); if (charPrefix == null) { continue; } if (uniqueCharacters.containsKey(charPrefix)) { // this character was already used, lets make it more unique. We first need to // resolve the existing character if it exists CharSequence existingName = uniqueCharacters.get(charPrefix); if (existingName != null) { uniqueNames.put(existingName, mPeopleHelper.findNameSplit(existingName)); uniqueCharacters.put(charPrefix, null); } uniqueNames.put(senderName, mPeopleHelper.findNameSplit(senderName)); } else { uniqueNames.put(senderName, charPrefix); uniqueCharacters.put(charPrefix, senderName); } } } Map<CharSequence, String> uniqueNames = mPeopleHelper.mapUniqueNamesToPrefix(mGroups); // Now that we have the correct symbols, let's look what we have cached ArrayMap<CharSequence, Icon> cachedAvatars = new ArrayMap<>(); Loading core/java/com/android/internal/widget/MessagingGroup.java +28 −11 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.annotation.StyleRes; import android.app.Person; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Resources; import android.graphics.Color; import android.graphics.Point; import android.graphics.Rect; Loading Loading @@ -109,7 +110,10 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou private boolean mIsInConversation = true; private ViewGroup mMessagingIconContainer; private int mConversationContentStart; private int mNonConversationMarginEnd; private int mNonConversationContentStart; private int mNonConversationPaddingStart; private int mConversationAvatarSize; private int mNonConversationAvatarSize; private int mNotificationTextMarginTop; public MessagingGroup(@NonNull Context context) { Loading Loading @@ -141,16 +145,21 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou mMessagingIconContainer = findViewById(R.id.message_icon_container); mContentContainer = findViewById(R.id.messaging_group_content_container); mSendingSpinnerContainer = findViewById(R.id.messaging_group_sending_progress_container); DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); Resources res = getResources(); DisplayMetrics displayMetrics = res.getDisplayMetrics(); mDisplaySize.x = displayMetrics.widthPixels; mDisplaySize.y = displayMetrics.heightPixels; mSenderTextPaddingSingleLine = getResources().getDimensionPixelSize( mSenderTextPaddingSingleLine = res.getDimensionPixelSize( R.dimen.messaging_group_singleline_sender_padding_end); mConversationContentStart = getResources().getDimensionPixelSize( R.dimen.conversation_content_start); mNonConversationMarginEnd = getResources().getDimensionPixelSize( R.dimen.messaging_layout_margin_end); mNotificationTextMarginTop = getResources().getDimensionPixelSize( mConversationContentStart = res.getDimensionPixelSize(R.dimen.conversation_content_start); mNonConversationContentStart = res.getDimensionPixelSize( R.dimen.notification_content_margin_start); mNonConversationPaddingStart = res.getDimensionPixelSize( R.dimen.messaging_layout_icon_padding_start); mConversationAvatarSize = res.getDimensionPixelSize(R.dimen.messaging_avatar_size); mNonConversationAvatarSize = res.getDimensionPixelSize( R.dimen.notification_icon_circle_size); mNotificationTextMarginTop = res.getDimensionPixelSize( R.dimen.notification_text_margin_top); } Loading Loading @@ -696,10 +705,18 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou mIsInConversation = isInConversation; MarginLayoutParams layoutParams = (MarginLayoutParams) mMessagingIconContainer.getLayoutParams(); layoutParams.width = mIsInConversation ? mConversationContentStart : ViewPager.LayoutParams.WRAP_CONTENT; layoutParams.setMarginEnd(mIsInConversation ? 0 : mNonConversationMarginEnd); layoutParams.width = mIsInConversation ? mConversationContentStart : mNonConversationContentStart; mMessagingIconContainer.setLayoutParams(layoutParams); int imagePaddingStart = isInConversation ? 0 : mNonConversationPaddingStart; mMessagingIconContainer.setPaddingRelative(imagePaddingStart, 0, 0, 0); ViewGroup.LayoutParams avatarLayoutParams = mAvatarView.getLayoutParams(); int size = mIsInConversation ? mConversationAvatarSize : mNonConversationAvatarSize; avatarLayoutParams.height = size; avatarLayoutParams.width = size; mAvatarView.setLayoutParams(avatarLayoutParams); } } Loading core/java/com/android/internal/widget/MessagingLayout.java +65 −87 File changed.Preview size limit exceeded, changes collapsed. Show changes core/java/com/android/internal/widget/PeopleHelper.java +58 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static com.android.internal.widget.MessagingPropertyAnimator.ALPHA_OUT; import android.annotation.ColorInt; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; Loading @@ -28,12 +29,15 @@ import android.graphics.Color; import android.graphics.Paint; import android.graphics.drawable.Icon; import android.text.TextUtils; import android.util.ArrayMap; import android.view.View; import com.android.internal.R; import com.android.internal.graphics.ColorUtils; import com.android.internal.util.ContrastColorUtil; import java.util.List; import java.util.Map; import java.util.regex.Pattern; /** Loading Loading @@ -176,4 +180,58 @@ public class PeopleHelper { } return findNamePrefix(name, ""); } /** * Creates a mapping of the unique sender names in the groups to the string 1- or 2-character * prefix strings for the names, which are extracted as the initials, and should be used for * generating the avatar. Senders not requiring a generated avatar, or with an empty name are * omitted. */ public Map<CharSequence, String> mapUniqueNamesToPrefix(List<MessagingGroup> groups) { // Map of unique names to their prefix ArrayMap<CharSequence, String> uniqueNames = new ArrayMap<>(); // Map of single-character string prefix to the only name which uses it, or null if multiple ArrayMap<String, CharSequence> uniqueCharacters = new ArrayMap<>(); for (int i = 0; i < groups.size(); i++) { MessagingGroup group = groups.get(i); CharSequence senderName = group.getSenderName(); if (!group.needsGeneratedAvatar() || TextUtils.isEmpty(senderName)) { continue; } if (!uniqueNames.containsKey(senderName)) { String charPrefix = findNamePrefix(senderName, null); if (charPrefix == null) { continue; } if (uniqueCharacters.containsKey(charPrefix)) { // this character was already used, lets make it more unique. We first need to // resolve the existing character if it exists CharSequence existingName = uniqueCharacters.get(charPrefix); if (existingName != null) { uniqueNames.put(existingName, findNameSplit(existingName)); uniqueCharacters.put(charPrefix, null); } uniqueNames.put(senderName, findNameSplit(senderName)); } else { uniqueNames.put(senderName, charPrefix); uniqueCharacters.put(charPrefix, senderName); } } } return uniqueNames; } /** * Update whether the groups can hide the sender if they are first * (happens only for 1:1 conversations where the given title matches the sender's name) */ public void maybeHideFirstSenderName(@NonNull List<MessagingGroup> groups, boolean isOneToOne, @Nullable CharSequence conversationTitle) { for (int i = groups.size() - 1; i >= 0; i--) { MessagingGroup messagingGroup = groups.get(i); CharSequence messageSender = messagingGroup.getSenderName(); boolean canHide = isOneToOne && TextUtils.equals(conversationTitle, messageSender); messagingGroup.setCanHideSenderIfFirst(canHide); } } } Loading
core/java/android/app/Notification.java +53 −30 Original line number Diff line number Diff line Loading @@ -5116,6 +5116,7 @@ public class Notification implements Parcelable TemplateBindResult result) { p.headerless(resId == getBaseLayoutResource() || resId == getHeadsUpBaseLayoutResource() || resId == getMessagingLayoutResource() || resId == R.layout.notification_template_material_media); RemoteViews contentView = new BuilderRemoteViews(mContext.getApplicationInfo(), resId); Loading Loading @@ -6641,6 +6642,10 @@ public class Notification implements Parcelable return R.layout.notification_template_material_messaging; } private int getBigMessagingLayoutResource() { return R.layout.notification_template_material_big_messaging; } private int getConversationLayoutResource() { return R.layout.notification_template_material_conversation; } Loading Loading @@ -8151,12 +8156,14 @@ public class Notification implements Parcelable */ @Override public RemoteViews makeContentView(boolean increasedHeight) { // All messaging templates contain the actions ArrayList<Action> originalActions = mBuilder.mActions; try { mBuilder.mActions = new ArrayList<>(); RemoteViews remoteViews = makeMessagingView(true /* isCollapsed */, false /* hideLargeIcon */); return makeMessagingView(StandardTemplateParams.VIEW_TYPE_NORMAL); } finally { mBuilder.mActions = originalActions; return remoteViews; } } /** Loading Loading @@ -8242,18 +8249,24 @@ public class Notification implements Parcelable */ @Override public RemoteViews makeBigContentView() { return makeMessagingView(false /* isCollapsed */, true /* hideLargeIcon */); return makeMessagingView(StandardTemplateParams.VIEW_TYPE_BIG); } /** * Create a messaging layout. * * @param isCollapsed Should this use the collapsed layout * @param hideRightIcons Should the reply affordance be shown at the end of the notification * @param viewType one of StandardTemplateParams.VIEW_TYPE_NORMAL, VIEW_TYPE_BIG, * VIEW_TYPE_HEADS_UP * @return the created remoteView. */ @NonNull private RemoteViews makeMessagingView(boolean isCollapsed, boolean hideRightIcons) { private RemoteViews makeMessagingView(int viewType) { boolean isCollapsed = viewType != StandardTemplateParams.VIEW_TYPE_BIG; boolean hideRightIcons = viewType != StandardTemplateParams.VIEW_TYPE_NORMAL; boolean isConversationLayout = mConversationType != CONVERSATION_TYPE_LEGACY; boolean isImportantConversation = mConversationType == CONVERSATION_TYPE_IMPORTANT; boolean isHeaderless = !isConversationLayout && isCollapsed; CharSequence conversationTitle = !TextUtils.isEmpty(super.mBigContentTitle) ? super.mBigContentTitle : mConversationTitle; Loading @@ -8271,23 +8284,26 @@ public class Notification implements Parcelable } else { isOneToOne = !isGroupConversation(); } boolean isConversationLayout = mConversationType != CONVERSATION_TYPE_LEGACY; boolean isImportantConversation = mConversationType == CONVERSATION_TYPE_IMPORTANT; if (isHeaderless && isOneToOne && TextUtils.isEmpty(conversationTitle)) { conversationTitle = getOtherPersonName(); } Icon largeIcon = mBuilder.mN.mLargeIcon; TemplateBindResult bindResult = new TemplateBindResult(); StandardTemplateParams p = mBuilder.mParams.reset() .viewType(isCollapsed ? StandardTemplateParams.VIEW_TYPE_NORMAL : StandardTemplateParams.VIEW_TYPE_BIG) .viewType(viewType) .highlightExpander(isConversationLayout) .hideProgress(true) .title(conversationTitle) .title(isHeaderless ? conversationTitle : null) .text(null) .hideLargeIcon(hideRightIcons || isOneToOne) .headerTextSecondary(conversationTitle); .headerTextSecondary(isHeaderless ? null : conversationTitle); RemoteViews contentView = mBuilder.applyStandardTemplateWithActions( isConversationLayout ? mBuilder.getConversationLayoutResource() : mBuilder.getMessagingLayoutResource(), : isCollapsed ? mBuilder.getMessagingLayoutResource() : mBuilder.getBigMessagingLayoutResource(), p, bindResult); if (isConversationLayout) { Loading @@ -8296,14 +8312,6 @@ public class Notification implements Parcelable } addExtras(mBuilder.mN.extras); if (!isConversationLayout) { // also update the end margin if there is an image // NOTE: This template doesn't support moving this icon to the left, so we don't // need to fully apply the MarginSet contentView.setViewLayoutMargin(R.id.notification_messaging, RemoteViews.MARGIN_END, bindResult.mHeadingExtraMarginSet.getDpValue(), TypedValue.COMPLEX_UNIT_DIP); } contentView.setInt(R.id.status_bar_latest_event_content, "setLayoutColor", mBuilder.getSmallIconColor(p)); contentView.setInt(R.id.status_bar_latest_event_content, "setSenderTextColor", Loading @@ -8329,6 +8337,10 @@ public class Notification implements Parcelable contentView.setBoolean(R.id.status_bar_latest_event_content, "setIsImportantConversation", isImportantConversation); } if (isHeaderless) { // Collapsed legacy messaging style has a 1-line limit. contentView.setInt(R.id.notification_messaging, "setMaxDisplayedLines", 1); } contentView.setIcon(R.id.status_bar_latest_event_content, "setLargeIcon", largeIcon); contentView.setBundle(R.id.status_bar_latest_event_content, "setData", Loading @@ -8336,6 +8348,22 @@ public class Notification implements Parcelable return contentView; } private CharSequence getKey(Person person) { return person == null ? null : person.getKey() == null ? person.getName() : person.getKey(); } private CharSequence getOtherPersonName() { CharSequence userKey = getKey(mUser); for (int i = mMessages.size() - 1; i >= 0; i--) { Person sender = mMessages.get(i).getSenderPerson(); if (sender != null && !TextUtils.equals(userKey, getKey(sender))) { return sender.getName(); } } return null; } private boolean hasOnlyWhiteSpaceSenders() { for (int i = 0; i < mMessages.size(); i++) { Message m = mMessages.get(i); Loading Loading @@ -8370,12 +8398,7 @@ public class Notification implements Parcelable */ @Override public RemoteViews makeHeadsUpContentView(boolean increasedHeight) { RemoteViews remoteViews = makeMessagingView(true /* isCollapsed */, true /* hideLargeIcon */); if (mConversationType == CONVERSATION_TYPE_LEGACY) { remoteViews.setInt(R.id.notification_messaging, "setMaxDisplayedLines", 1); } return remoteViews; return makeMessagingView(StandardTemplateParams.VIEW_TYPE_HEADS_UP); } public static final class Message { Loading
core/java/com/android/internal/widget/ConversationLayout.java +3 −36 Original line number Diff line number Diff line Loading @@ -64,6 +64,7 @@ import com.android.internal.R; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.function.Consumer; Loading Loading @@ -530,13 +531,7 @@ public class ConversationLayout extends FrameLayout mConversationText.setText(conversationText); // Update if the groups can hide the sender if they are first (applies to 1:1 conversations) // This needs to happen after all of the above o update all of the groups for (int i = mGroups.size() - 1; i >= 0; i--) { MessagingGroup messagingGroup = mGroups.get(i); CharSequence messageSender = messagingGroup.getSenderName(); boolean canHide = mIsOneToOne && TextUtils.equals(conversationText, messageSender); messagingGroup.setCanHideSenderIfFirst(canHide); } mPeopleHelper.maybeHideFirstSenderName(mGroups, mIsOneToOne, conversationText); updateAppName(); updateIconPositionAndSize(); updateImageMessages(); Loading Loading @@ -779,35 +774,7 @@ public class ConversationLayout extends FrameLayout private void updateTitleAndNamesDisplay() { // Map of unique names to their prefix ArrayMap<CharSequence, String> uniqueNames = new ArrayMap<>(); // Map of single-character string prefix to the only name which uses it, or null if multiple ArrayMap<String, CharSequence> uniqueCharacters = new ArrayMap<>(); for (int i = 0; i < mGroups.size(); i++) { MessagingGroup group = mGroups.get(i); CharSequence senderName = group.getSenderName(); if (!group.needsGeneratedAvatar() || TextUtils.isEmpty(senderName)) { continue; } if (!uniqueNames.containsKey(senderName)) { String charPrefix = mPeopleHelper.findNamePrefix(senderName, null); if (charPrefix == null) { continue; } if (uniqueCharacters.containsKey(charPrefix)) { // this character was already used, lets make it more unique. We first need to // resolve the existing character if it exists CharSequence existingName = uniqueCharacters.get(charPrefix); if (existingName != null) { uniqueNames.put(existingName, mPeopleHelper.findNameSplit(existingName)); uniqueCharacters.put(charPrefix, null); } uniqueNames.put(senderName, mPeopleHelper.findNameSplit(senderName)); } else { uniqueNames.put(senderName, charPrefix); uniqueCharacters.put(charPrefix, senderName); } } } Map<CharSequence, String> uniqueNames = mPeopleHelper.mapUniqueNamesToPrefix(mGroups); // Now that we have the correct symbols, let's look what we have cached ArrayMap<CharSequence, Icon> cachedAvatars = new ArrayMap<>(); Loading
core/java/com/android/internal/widget/MessagingGroup.java +28 −11 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.annotation.StyleRes; import android.app.Person; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Resources; import android.graphics.Color; import android.graphics.Point; import android.graphics.Rect; Loading Loading @@ -109,7 +110,10 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou private boolean mIsInConversation = true; private ViewGroup mMessagingIconContainer; private int mConversationContentStart; private int mNonConversationMarginEnd; private int mNonConversationContentStart; private int mNonConversationPaddingStart; private int mConversationAvatarSize; private int mNonConversationAvatarSize; private int mNotificationTextMarginTop; public MessagingGroup(@NonNull Context context) { Loading Loading @@ -141,16 +145,21 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou mMessagingIconContainer = findViewById(R.id.message_icon_container); mContentContainer = findViewById(R.id.messaging_group_content_container); mSendingSpinnerContainer = findViewById(R.id.messaging_group_sending_progress_container); DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); Resources res = getResources(); DisplayMetrics displayMetrics = res.getDisplayMetrics(); mDisplaySize.x = displayMetrics.widthPixels; mDisplaySize.y = displayMetrics.heightPixels; mSenderTextPaddingSingleLine = getResources().getDimensionPixelSize( mSenderTextPaddingSingleLine = res.getDimensionPixelSize( R.dimen.messaging_group_singleline_sender_padding_end); mConversationContentStart = getResources().getDimensionPixelSize( R.dimen.conversation_content_start); mNonConversationMarginEnd = getResources().getDimensionPixelSize( R.dimen.messaging_layout_margin_end); mNotificationTextMarginTop = getResources().getDimensionPixelSize( mConversationContentStart = res.getDimensionPixelSize(R.dimen.conversation_content_start); mNonConversationContentStart = res.getDimensionPixelSize( R.dimen.notification_content_margin_start); mNonConversationPaddingStart = res.getDimensionPixelSize( R.dimen.messaging_layout_icon_padding_start); mConversationAvatarSize = res.getDimensionPixelSize(R.dimen.messaging_avatar_size); mNonConversationAvatarSize = res.getDimensionPixelSize( R.dimen.notification_icon_circle_size); mNotificationTextMarginTop = res.getDimensionPixelSize( R.dimen.notification_text_margin_top); } Loading Loading @@ -696,10 +705,18 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou mIsInConversation = isInConversation; MarginLayoutParams layoutParams = (MarginLayoutParams) mMessagingIconContainer.getLayoutParams(); layoutParams.width = mIsInConversation ? mConversationContentStart : ViewPager.LayoutParams.WRAP_CONTENT; layoutParams.setMarginEnd(mIsInConversation ? 0 : mNonConversationMarginEnd); layoutParams.width = mIsInConversation ? mConversationContentStart : mNonConversationContentStart; mMessagingIconContainer.setLayoutParams(layoutParams); int imagePaddingStart = isInConversation ? 0 : mNonConversationPaddingStart; mMessagingIconContainer.setPaddingRelative(imagePaddingStart, 0, 0, 0); ViewGroup.LayoutParams avatarLayoutParams = mAvatarView.getLayoutParams(); int size = mIsInConversation ? mConversationAvatarSize : mNonConversationAvatarSize; avatarLayoutParams.height = size; avatarLayoutParams.width = size; mAvatarView.setLayoutParams(avatarLayoutParams); } } Loading
core/java/com/android/internal/widget/MessagingLayout.java +65 −87 File changed.Preview size limit exceeded, changes collapsed. Show changes
core/java/com/android/internal/widget/PeopleHelper.java +58 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static com.android.internal.widget.MessagingPropertyAnimator.ALPHA_OUT; import android.annotation.ColorInt; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; Loading @@ -28,12 +29,15 @@ import android.graphics.Color; import android.graphics.Paint; import android.graphics.drawable.Icon; import android.text.TextUtils; import android.util.ArrayMap; import android.view.View; import com.android.internal.R; import com.android.internal.graphics.ColorUtils; import com.android.internal.util.ContrastColorUtil; import java.util.List; import java.util.Map; import java.util.regex.Pattern; /** Loading Loading @@ -176,4 +180,58 @@ public class PeopleHelper { } return findNamePrefix(name, ""); } /** * Creates a mapping of the unique sender names in the groups to the string 1- or 2-character * prefix strings for the names, which are extracted as the initials, and should be used for * generating the avatar. Senders not requiring a generated avatar, or with an empty name are * omitted. */ public Map<CharSequence, String> mapUniqueNamesToPrefix(List<MessagingGroup> groups) { // Map of unique names to their prefix ArrayMap<CharSequence, String> uniqueNames = new ArrayMap<>(); // Map of single-character string prefix to the only name which uses it, or null if multiple ArrayMap<String, CharSequence> uniqueCharacters = new ArrayMap<>(); for (int i = 0; i < groups.size(); i++) { MessagingGroup group = groups.get(i); CharSequence senderName = group.getSenderName(); if (!group.needsGeneratedAvatar() || TextUtils.isEmpty(senderName)) { continue; } if (!uniqueNames.containsKey(senderName)) { String charPrefix = findNamePrefix(senderName, null); if (charPrefix == null) { continue; } if (uniqueCharacters.containsKey(charPrefix)) { // this character was already used, lets make it more unique. We first need to // resolve the existing character if it exists CharSequence existingName = uniqueCharacters.get(charPrefix); if (existingName != null) { uniqueNames.put(existingName, findNameSplit(existingName)); uniqueCharacters.put(charPrefix, null); } uniqueNames.put(senderName, findNameSplit(senderName)); } else { uniqueNames.put(senderName, charPrefix); uniqueCharacters.put(charPrefix, senderName); } } } return uniqueNames; } /** * Update whether the groups can hide the sender if they are first * (happens only for 1:1 conversations where the given title matches the sender's name) */ public void maybeHideFirstSenderName(@NonNull List<MessagingGroup> groups, boolean isOneToOne, @Nullable CharSequence conversationTitle) { for (int i = groups.size() - 1; i >= 0; i--) { MessagingGroup messagingGroup = groups.get(i); CharSequence messageSender = messagingGroup.getSenderName(); boolean canHide = isOneToOne && TextUtils.equals(conversationTitle, messageSender); messagingGroup.setCanHideSenderIfFirst(canHide); } } }