Loading core/java/android/app/Notification.java +28 −0 Original line number Diff line number Diff line Loading @@ -5487,6 +5487,15 @@ public class Notification implements Parcelable return mColors; } /** * @param isHeader If the notification is a notification header * @return An instance of mColors after resolving the palette */ private Colors getColors(boolean isHeader) { mColors.resolvePalette(mContext, mN.color, !isHeader && mN.isColorized(), mInNightMode); return mColors; } private void updateBackgroundColor(RemoteViews contentView, StandardTemplateParams p) { if (isBackgroundColorized(p)) { Loading Loading @@ -6618,6 +6627,23 @@ public class Notification implements Parcelable return getColors(p).getContrastColor(); } /** * Gets the foreground color of the small icon. If the notification is colorized, this * is the primary text color, otherwise it's the contrast-adjusted app-provided color. * @hide */ public @ColorInt int getSmallIconColor(boolean isHeader) { return getColors(/* isHeader = */ isHeader).getContrastColor(); } /** * Gets the background color of the notification. * @hide */ public @ColorInt int getBackgroundColor(boolean isHeader) { return getColors(/* isHeader = */ isHeader).getBackgroundColor(); } /** @return the theme's accent color for colored UI elements. */ private @ColorInt int getPrimaryAccentColor(StandardTemplateParams p) { return getColors(p).getPrimaryAccentColor(); Loading Loading @@ -8532,6 +8558,8 @@ public class Notification implements Parcelable boolean isImportantConversation = mConversationType == CONVERSATION_TYPE_IMPORTANT; boolean isHeaderless = !isConversationLayout && isCollapsed; //TODO (b/217799515): ensure mConversationTitle always returns the correct // conversationTitle, probably set mConversationTitle = conversationTitle after this CharSequence conversationTitle = !TextUtils.isEmpty(super.mBigContentTitle) ? super.mBigContentTitle : mConversationTitle; Loading core/java/com/android/internal/widget/ConversationLayout.java +29 −8 Original line number Diff line number Diff line Loading @@ -105,6 +105,9 @@ public class ConversationLayout extends FrameLayout private int mConversationIconTopPaddingExpandedGroup; private int mConversationIconTopPadding; private int mExpandedGroupMessagePadding; // TODO (b/217799515) Currently, mConversationText shows the conversation title, the actual // conversation text is inside of mMessagingLinearLayout, which is misleading, we should rename // this to mConversationTitleView private TextView mConversationText; private View mConversationIconBadge; private CachingIconView mConversationIconBadgeBg; Loading @@ -125,6 +128,11 @@ public class ConversationLayout extends FrameLayout private int mNotificationBackgroundColor; private CharSequence mFallbackChatName; private CharSequence mFallbackGroupChatName; //TODO (b/217799515) Currently, Notification.MessagingStyle, ConversationLayout, and // HybridConversationNotificationView, each has their own definition of "ConversationTitle". // What make things worse is that the term of "ConversationTitle" often confuses with // "ConversationText". // We need to unify them or differentiate the namings. private CharSequence mConversationTitle; private int mMessageSpacingStandard; private int mMessageSpacingGroup; Loading Loading @@ -297,13 +305,17 @@ public class ConversationLayout extends FrameLayout mNameReplacement = nameReplacement; } /** Sets this conversation as "important", adding some additional UI treatment. */ /** * Sets this conversation as "important", adding some additional UI treatment. */ @RemotableViewMethod public void setIsImportantConversation(boolean isImportantConversation) { setIsImportantConversation(isImportantConversation, false); } /** @hide **/ /** * @hide **/ public void setIsImportantConversation(boolean isImportantConversation, boolean animate) { mImportantConversation = isImportantConversation; mImportanceRingView.setVisibility(isImportantConversation && mIcon.getVisibility() != GONE Loading Loading @@ -386,6 +398,7 @@ public class ConversationLayout extends FrameLayout /** * Set conversation data * * @param extras Bundle contains conversation data */ @RemotableViewMethod(asyncImpl = "setDataAsync") Loading Loading @@ -427,6 +440,7 @@ public class ConversationLayout 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 conversation data * @hide */ Loading @@ -449,6 +463,7 @@ public class ConversationLayout extends FrameLayout /** * enable/disable precomputed text usage * * @hide */ public void setPrecomputedTextEnabled(boolean precomputedTextEnabled) { Loading @@ -466,7 +481,9 @@ public class ConversationLayout extends FrameLayout mImageResolver = resolver; } /** @hide */ /** * @hide */ public void setUnreadCount(int unreadCount) { mExpandButton.setNumber(unreadCount); } Loading Loading @@ -795,6 +812,10 @@ public class ConversationLayout extends FrameLayout mConversationTitle = conversationTitle != null ? conversationTitle.toString() : null; } // TODO (b/217799515) getConversationTitle is not consistent with setConversationTitle // if you call getConversationTitle() immediately after setConversationTitle(), the result // will not correctly reflect the new change without calling updateConversationLayout, for // example. public CharSequence getConversationTitle() { return mConversationText.getText(); } Loading core/java/com/android/internal/widget/PeopleHelper.java +68 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ import static com.android.internal.widget.MessagingPropertyAnimator.ALPHA_OUT; import android.annotation.ColorInt; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Notification; import android.app.Person; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; Loading Loading @@ -221,6 +223,72 @@ public class PeopleHelper { return uniqueNames; } /** * A class that represents a map from unique sender names in the groups to the string 1- or * 2-character prefix strings for the names. This class uses the String value of the * CharSequence Names as the key. */ public class NameToPrefixMap { Map<String, String> mMap; NameToPrefixMap(Map<String, String> map) { this.mMap = map; } /** * @param name the name * @return the prefix of the given name */ public String getPrefix(CharSequence name) { return mMap.get(name.toString()); } } /** * Same functionality as mapUniqueNamesToPrefix, but takes list-represented message groups as * the input. This method is better when inflating MessagingGroup from the UI thread is not * an option. * @param groups message groups represented by lists. A message group is some consecutive * messages (>=3) from the same sender in a conversation. */ public NameToPrefixMap mapUniqueNamesToPrefixWithGroupList( List<List<Notification.MessagingStyle.Message>> groups) { // Map of unique names to their prefix ArrayMap<String, 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++) { List<Notification.MessagingStyle.Message> group = groups.get(i); if (group.isEmpty()) continue; Person sender = group.get(0).getSenderPerson(); if (sender == null) continue; CharSequence senderName = sender.getName(); if (sender.getIcon() != null || TextUtils.isEmpty(senderName)) { continue; } String senderNameString = senderName.toString(); if (!uniqueNames.containsKey(senderNameString)) { 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.toString(), findNameSplit(existingName)); uniqueCharacters.put(charPrefix, null); } uniqueNames.put(senderNameString, findNameSplit(senderName)); } else { uniqueNames.put(senderNameString, charPrefix); uniqueCharacters.put(charPrefix, senderName); } } } return new NameToPrefixMap(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) Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt +3 −2 Original line number Diff line number Diff line Loading @@ -52,8 +52,8 @@ class ConversationNotificationProcessor @Inject constructor( entry: NotificationEntry, recoveredBuilder: Notification.Builder, logger: NotificationContentInflaterLogger ) { val messagingStyle = recoveredBuilder.style as? Notification.MessagingStyle ?: return ): Notification.MessagingStyle? { val messagingStyle = recoveredBuilder.style as? Notification.MessagingStyle ?: return null messagingStyle.conversationType = if (entry.ranking.channel.isImportantConversation) Notification.MessagingStyle.CONVERSATION_TYPE_IMPORTANT Loading @@ -68,6 +68,7 @@ class ConversationNotificationProcessor @Inject constructor( } messagingStyle.unreadMessageCount = conversationNotificationManager.getUnreadCount(entry, recoveredBuilder) return messagingStyle } } Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java +6 −2 Original line number Diff line number Diff line Loading @@ -362,8 +362,12 @@ public class PreparationCoordinator implements Coordinator { } NotifInflater.Params getInflaterParams(NotifUiAdjustment adjustment, String reason) { return new NotifInflater.Params(adjustment.isMinimized(), reason, adjustment.isSnoozeEnabled()); return new NotifInflater.Params( adjustment.isMinimized(), reason, adjustment.isSnoozeEnabled(), adjustment.isChildInGroup() ); } private void abortInflation(NotificationEntry entry, String reason) { Loading Loading
core/java/android/app/Notification.java +28 −0 Original line number Diff line number Diff line Loading @@ -5487,6 +5487,15 @@ public class Notification implements Parcelable return mColors; } /** * @param isHeader If the notification is a notification header * @return An instance of mColors after resolving the palette */ private Colors getColors(boolean isHeader) { mColors.resolvePalette(mContext, mN.color, !isHeader && mN.isColorized(), mInNightMode); return mColors; } private void updateBackgroundColor(RemoteViews contentView, StandardTemplateParams p) { if (isBackgroundColorized(p)) { Loading Loading @@ -6618,6 +6627,23 @@ public class Notification implements Parcelable return getColors(p).getContrastColor(); } /** * Gets the foreground color of the small icon. If the notification is colorized, this * is the primary text color, otherwise it's the contrast-adjusted app-provided color. * @hide */ public @ColorInt int getSmallIconColor(boolean isHeader) { return getColors(/* isHeader = */ isHeader).getContrastColor(); } /** * Gets the background color of the notification. * @hide */ public @ColorInt int getBackgroundColor(boolean isHeader) { return getColors(/* isHeader = */ isHeader).getBackgroundColor(); } /** @return the theme's accent color for colored UI elements. */ private @ColorInt int getPrimaryAccentColor(StandardTemplateParams p) { return getColors(p).getPrimaryAccentColor(); Loading Loading @@ -8532,6 +8558,8 @@ public class Notification implements Parcelable boolean isImportantConversation = mConversationType == CONVERSATION_TYPE_IMPORTANT; boolean isHeaderless = !isConversationLayout && isCollapsed; //TODO (b/217799515): ensure mConversationTitle always returns the correct // conversationTitle, probably set mConversationTitle = conversationTitle after this CharSequence conversationTitle = !TextUtils.isEmpty(super.mBigContentTitle) ? super.mBigContentTitle : mConversationTitle; Loading
core/java/com/android/internal/widget/ConversationLayout.java +29 −8 Original line number Diff line number Diff line Loading @@ -105,6 +105,9 @@ public class ConversationLayout extends FrameLayout private int mConversationIconTopPaddingExpandedGroup; private int mConversationIconTopPadding; private int mExpandedGroupMessagePadding; // TODO (b/217799515) Currently, mConversationText shows the conversation title, the actual // conversation text is inside of mMessagingLinearLayout, which is misleading, we should rename // this to mConversationTitleView private TextView mConversationText; private View mConversationIconBadge; private CachingIconView mConversationIconBadgeBg; Loading @@ -125,6 +128,11 @@ public class ConversationLayout extends FrameLayout private int mNotificationBackgroundColor; private CharSequence mFallbackChatName; private CharSequence mFallbackGroupChatName; //TODO (b/217799515) Currently, Notification.MessagingStyle, ConversationLayout, and // HybridConversationNotificationView, each has their own definition of "ConversationTitle". // What make things worse is that the term of "ConversationTitle" often confuses with // "ConversationText". // We need to unify them or differentiate the namings. private CharSequence mConversationTitle; private int mMessageSpacingStandard; private int mMessageSpacingGroup; Loading Loading @@ -297,13 +305,17 @@ public class ConversationLayout extends FrameLayout mNameReplacement = nameReplacement; } /** Sets this conversation as "important", adding some additional UI treatment. */ /** * Sets this conversation as "important", adding some additional UI treatment. */ @RemotableViewMethod public void setIsImportantConversation(boolean isImportantConversation) { setIsImportantConversation(isImportantConversation, false); } /** @hide **/ /** * @hide **/ public void setIsImportantConversation(boolean isImportantConversation, boolean animate) { mImportantConversation = isImportantConversation; mImportanceRingView.setVisibility(isImportantConversation && mIcon.getVisibility() != GONE Loading Loading @@ -386,6 +398,7 @@ public class ConversationLayout extends FrameLayout /** * Set conversation data * * @param extras Bundle contains conversation data */ @RemotableViewMethod(asyncImpl = "setDataAsync") Loading Loading @@ -427,6 +440,7 @@ public class ConversationLayout 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 conversation data * @hide */ Loading @@ -449,6 +463,7 @@ public class ConversationLayout extends FrameLayout /** * enable/disable precomputed text usage * * @hide */ public void setPrecomputedTextEnabled(boolean precomputedTextEnabled) { Loading @@ -466,7 +481,9 @@ public class ConversationLayout extends FrameLayout mImageResolver = resolver; } /** @hide */ /** * @hide */ public void setUnreadCount(int unreadCount) { mExpandButton.setNumber(unreadCount); } Loading Loading @@ -795,6 +812,10 @@ public class ConversationLayout extends FrameLayout mConversationTitle = conversationTitle != null ? conversationTitle.toString() : null; } // TODO (b/217799515) getConversationTitle is not consistent with setConversationTitle // if you call getConversationTitle() immediately after setConversationTitle(), the result // will not correctly reflect the new change without calling updateConversationLayout, for // example. public CharSequence getConversationTitle() { return mConversationText.getText(); } Loading
core/java/com/android/internal/widget/PeopleHelper.java +68 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ import static com.android.internal.widget.MessagingPropertyAnimator.ALPHA_OUT; import android.annotation.ColorInt; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Notification; import android.app.Person; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; Loading Loading @@ -221,6 +223,72 @@ public class PeopleHelper { return uniqueNames; } /** * A class that represents a map from unique sender names in the groups to the string 1- or * 2-character prefix strings for the names. This class uses the String value of the * CharSequence Names as the key. */ public class NameToPrefixMap { Map<String, String> mMap; NameToPrefixMap(Map<String, String> map) { this.mMap = map; } /** * @param name the name * @return the prefix of the given name */ public String getPrefix(CharSequence name) { return mMap.get(name.toString()); } } /** * Same functionality as mapUniqueNamesToPrefix, but takes list-represented message groups as * the input. This method is better when inflating MessagingGroup from the UI thread is not * an option. * @param groups message groups represented by lists. A message group is some consecutive * messages (>=3) from the same sender in a conversation. */ public NameToPrefixMap mapUniqueNamesToPrefixWithGroupList( List<List<Notification.MessagingStyle.Message>> groups) { // Map of unique names to their prefix ArrayMap<String, 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++) { List<Notification.MessagingStyle.Message> group = groups.get(i); if (group.isEmpty()) continue; Person sender = group.get(0).getSenderPerson(); if (sender == null) continue; CharSequence senderName = sender.getName(); if (sender.getIcon() != null || TextUtils.isEmpty(senderName)) { continue; } String senderNameString = senderName.toString(); if (!uniqueNames.containsKey(senderNameString)) { 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.toString(), findNameSplit(existingName)); uniqueCharacters.put(charPrefix, null); } uniqueNames.put(senderNameString, findNameSplit(senderName)); } else { uniqueNames.put(senderNameString, charPrefix); uniqueCharacters.put(charPrefix, senderName); } } } return new NameToPrefixMap(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) Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt +3 −2 Original line number Diff line number Diff line Loading @@ -52,8 +52,8 @@ class ConversationNotificationProcessor @Inject constructor( entry: NotificationEntry, recoveredBuilder: Notification.Builder, logger: NotificationContentInflaterLogger ) { val messagingStyle = recoveredBuilder.style as? Notification.MessagingStyle ?: return ): Notification.MessagingStyle? { val messagingStyle = recoveredBuilder.style as? Notification.MessagingStyle ?: return null messagingStyle.conversationType = if (entry.ranking.channel.isImportantConversation) Notification.MessagingStyle.CONVERSATION_TYPE_IMPORTANT Loading @@ -68,6 +68,7 @@ class ConversationNotificationProcessor @Inject constructor( } messagingStyle.unreadMessageCount = conversationNotificationManager.getUnreadCount(entry, recoveredBuilder) return messagingStyle } } Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java +6 −2 Original line number Diff line number Diff line Loading @@ -362,8 +362,12 @@ public class PreparationCoordinator implements Coordinator { } NotifInflater.Params getInflaterParams(NotifUiAdjustment adjustment, String reason) { return new NotifInflater.Params(adjustment.isMinimized(), reason, adjustment.isSnoozeEnabled()); return new NotifInflater.Params( adjustment.isMinimized(), reason, adjustment.isSnoozeEnabled(), adjustment.isChildInGroup() ); } private void abortInflation(NotificationEntry entry, String reason) { Loading