Loading core/java/android/app/Notification.java +19 −0 Original line number Diff line number Diff line Loading @@ -1232,6 +1232,10 @@ public class Notification implements Parcelable /** @hide */ public static final String EXTRA_CONVERSATION_ICON = "android.conversationIcon"; /** @hide */ public static final String EXTRA_CONVERSATION_UNREAD_MESSAGE_COUNT = "android.conversationUnreadMessageCount"; /** * {@link #extras} key: an array of {@link android.app.Notification.MessagingStyle.Message} * bundles provided by a Loading Loading @@ -7102,6 +7106,7 @@ public class Notification implements Parcelable List<Message> mHistoricMessages = new ArrayList<>(); boolean mIsGroupConversation; @ConversationType int mConversationType = CONVERSATION_TYPE_LEGACY; int mUnreadMessageCount; MessagingStyle() { } Loading Loading @@ -7247,6 +7252,17 @@ public class Notification implements Parcelable return mConversationType; } /** @hide */ public int getUnreadMessageCount() { return mUnreadMessageCount; } /** @hide */ public MessagingStyle setUnreadMessageCount(int unreadMessageCount) { mUnreadMessageCount = unreadMessageCount; return this; } /** * Adds a message for display by this notification. Convenience call for a simple * {@link Message} in {@link #addMessage(Notification.MessagingStyle.Message)}. Loading Loading @@ -7401,6 +7417,7 @@ public class Notification implements Parcelable if (mShortcutIcon != null) { extras.putParcelable(EXTRA_CONVERSATION_ICON, mShortcutIcon); } extras.putInt(EXTRA_CONVERSATION_UNREAD_MESSAGE_COUNT, mUnreadMessageCount); fixTitleAndTextExtras(extras); extras.putBoolean(EXTRA_IS_GROUP_CONVERSATION, mIsGroupConversation); Loading Loading @@ -7452,6 +7469,7 @@ public class Notification implements Parcelable Parcelable[] histMessages = extras.getParcelableArray(EXTRA_HISTORIC_MESSAGES); mHistoricMessages = Message.getMessagesFromBundleArray(histMessages); mIsGroupConversation = extras.getBoolean(EXTRA_IS_GROUP_CONVERSATION); mUnreadMessageCount = extras.getInt(EXTRA_CONVERSATION_UNREAD_MESSAGE_COUNT); } /** Loading Loading @@ -7601,6 +7619,7 @@ public class Notification implements Parcelable : mBuilder.getMessagingLayoutResource(), p, bindResult); addExtras(mBuilder.mN.extras); if (!isConversationLayout) { // also update the end margin if there is an image Loading core/java/com/android/internal/widget/ConversationLayout.java +18 −2 Original line number Diff line number Diff line Loading @@ -62,6 +62,7 @@ import com.android.internal.util.ContrastColorUtil; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.function.Consumer; import java.util.regex.Pattern; Loading Loading @@ -151,6 +152,7 @@ public class ConversationLayout extends FrameLayout private int mFacePileProtectionWidth; private int mFacePileProtectionWidthExpanded; private boolean mImportantConversation; private TextView mUnreadBadge; public ConversationLayout(@NonNull Context context) { super(context); Loading Loading @@ -277,6 +279,7 @@ public class ConversationLayout extends FrameLayout mAppName.setOnVisibilityChangedListener((visibility) -> { onAppNameVisibilityChanged(); }); mUnreadBadge = findViewById(R.id.conversation_unread_count); mConversationContentStart = getResources().getDimensionPixelSize( R.dimen.conversation_content_start); mInternalButtonPadding Loading Loading @@ -354,7 +357,6 @@ public class ConversationLayout extends FrameLayout // mUser now set (would be nice to avoid the side effect but WHATEVER) setUser(extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON)); // Append remote input history to newMessages (again, side effect is lame but WHATEVS) RemoteInputHistoryItem[] history = (RemoteInputHistoryItem[]) extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS); Loading @@ -362,9 +364,11 @@ public class ConversationLayout extends FrameLayout boolean showSpinner = extras.getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false); // bind it, baby bind(newMessages, newHistoricMessages, showSpinner); int unreadCount = extras.getInt(Notification.EXTRA_CONVERSATION_UNREAD_MESSAGE_COUNT); setUnreadCount(unreadCount); } @Override Loading @@ -372,6 +376,18 @@ public class ConversationLayout extends FrameLayout mImageResolver = resolver; } /** @hide */ public void setUnreadCount(int unreadCount) { mUnreadBadge.setVisibility(mIsCollapsed && unreadCount > 1 ? VISIBLE : GONE); CharSequence text = unreadCount >= 100 ? getResources().getString(R.string.unread_convo_overflow, 99) : String.format(Locale.getDefault(), "%d", unreadCount); mUnreadBadge.setText(text); mUnreadBadge.setBackgroundTintList(ColorStateList.valueOf(mLayoutColor)); boolean needDarkText = ColorUtils.calculateLuminance(mLayoutColor) > 0.5f; mUnreadBadge.setTextColor(needDarkText ? Color.BLACK : Color.WHITE); } private void addRemoteInputHistoryToMessages( List<Notification.MessagingStyle.Message> newMessages, RemoteInputHistoryItem[] remoteInputHistory) { Loading core/res/res/drawable/conversation_unread_bg.xml 0 → 100644 +19 −0 Original line number Diff line number Diff line <!-- ~ Copyright (C) 2020 The Android Open Source Project ~ ~ Licensed under the Apache License, Version 2.0 (the "License"); ~ you may not use this file except in compliance with the License. ~ You may obtain a copy of the License at ~ ~ http://www.apache.org/licenses/LICENSE-2.0 ~ ~ Unless required by applicable law or agreed to in writing, software ~ distributed under the License is distributed on an "AS IS" BASIS, ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ~ See the License for the specific language governing permissions and ~ limitations under the License. --> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <corners android:radius="20sp" /> <solid android:color="@android:color/white" /> </shape> No newline at end of file core/res/res/layout/notification_template_material_conversation.xml +17 −4 Original line number Diff line number Diff line Loading @@ -199,10 +199,8 @@ android:clipChildren="false" /> </com.android.internal.widget.RemeasuringLinearLayout> <!-- Unread Count --> <!-- <TextView /> --> <!-- This is where the expand button will be placed when collapsed--> <!-- This is where the expand button container will be placed when collapsed--> </com.android.internal.widget.RemeasuringLinearLayout> <include layout="@layout/notification_template_smart_reply_container" Loading Loading @@ -238,6 +236,21 @@ android:clipToPadding="false" android:clipChildren="false" /> <!-- Unread Count --> <TextView android:id="@+id/conversation_unread_count" android:layout_width="33sp" android:layout_height="wrap_content" android:layout_marginEnd="11dp" android:layout_gravity="center" android:gravity="center" android:padding="2dp" android:visibility="gone" android:textAppearance="@style/TextAppearance.DeviceDefault.Notification" android:textColor="#FFFFFF" android:textSize="12sp" android:background="@drawable/conversation_unread_bg" /> <com.android.internal.widget.NotificationExpandButton android:id="@+id/expand_button" android:layout_width="@dimen/notification_header_expand_icon_size" Loading core/res/res/values/strings.xml +3 −0 Original line number Diff line number Diff line Loading @@ -5442,6 +5442,9 @@ <!-- Conversation Title fallback if the there is no name provided in a group chat conversation [CHAR LIMIT=40]--> <string name="conversation_title_fallback_group_chat">Group Conversation</string> <!-- Number of unread messages displayed on a conversation notification, when greater-than-or-equal-to 100 [CHAR LIMIT=3]--> <string name="unread_convo_overflow"><xliff:g id="max_unread_count" example="99">%1$d</xliff:g>+</string> <!-- ResolverActivity - profile tabs --> <!-- Label of a tab on a screen. A user can tap this tap to switch to the 'Personal' view (that shows their personal content) if they have a work profile on their device. [CHAR LIMIT=NONE] --> <string name="resolver_personal_tab">Personal</string> Loading Loading
core/java/android/app/Notification.java +19 −0 Original line number Diff line number Diff line Loading @@ -1232,6 +1232,10 @@ public class Notification implements Parcelable /** @hide */ public static final String EXTRA_CONVERSATION_ICON = "android.conversationIcon"; /** @hide */ public static final String EXTRA_CONVERSATION_UNREAD_MESSAGE_COUNT = "android.conversationUnreadMessageCount"; /** * {@link #extras} key: an array of {@link android.app.Notification.MessagingStyle.Message} * bundles provided by a Loading Loading @@ -7102,6 +7106,7 @@ public class Notification implements Parcelable List<Message> mHistoricMessages = new ArrayList<>(); boolean mIsGroupConversation; @ConversationType int mConversationType = CONVERSATION_TYPE_LEGACY; int mUnreadMessageCount; MessagingStyle() { } Loading Loading @@ -7247,6 +7252,17 @@ public class Notification implements Parcelable return mConversationType; } /** @hide */ public int getUnreadMessageCount() { return mUnreadMessageCount; } /** @hide */ public MessagingStyle setUnreadMessageCount(int unreadMessageCount) { mUnreadMessageCount = unreadMessageCount; return this; } /** * Adds a message for display by this notification. Convenience call for a simple * {@link Message} in {@link #addMessage(Notification.MessagingStyle.Message)}. Loading Loading @@ -7401,6 +7417,7 @@ public class Notification implements Parcelable if (mShortcutIcon != null) { extras.putParcelable(EXTRA_CONVERSATION_ICON, mShortcutIcon); } extras.putInt(EXTRA_CONVERSATION_UNREAD_MESSAGE_COUNT, mUnreadMessageCount); fixTitleAndTextExtras(extras); extras.putBoolean(EXTRA_IS_GROUP_CONVERSATION, mIsGroupConversation); Loading Loading @@ -7452,6 +7469,7 @@ public class Notification implements Parcelable Parcelable[] histMessages = extras.getParcelableArray(EXTRA_HISTORIC_MESSAGES); mHistoricMessages = Message.getMessagesFromBundleArray(histMessages); mIsGroupConversation = extras.getBoolean(EXTRA_IS_GROUP_CONVERSATION); mUnreadMessageCount = extras.getInt(EXTRA_CONVERSATION_UNREAD_MESSAGE_COUNT); } /** Loading Loading @@ -7601,6 +7619,7 @@ public class Notification implements Parcelable : mBuilder.getMessagingLayoutResource(), p, bindResult); addExtras(mBuilder.mN.extras); if (!isConversationLayout) { // also update the end margin if there is an image Loading
core/java/com/android/internal/widget/ConversationLayout.java +18 −2 Original line number Diff line number Diff line Loading @@ -62,6 +62,7 @@ import com.android.internal.util.ContrastColorUtil; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.function.Consumer; import java.util.regex.Pattern; Loading Loading @@ -151,6 +152,7 @@ public class ConversationLayout extends FrameLayout private int mFacePileProtectionWidth; private int mFacePileProtectionWidthExpanded; private boolean mImportantConversation; private TextView mUnreadBadge; public ConversationLayout(@NonNull Context context) { super(context); Loading Loading @@ -277,6 +279,7 @@ public class ConversationLayout extends FrameLayout mAppName.setOnVisibilityChangedListener((visibility) -> { onAppNameVisibilityChanged(); }); mUnreadBadge = findViewById(R.id.conversation_unread_count); mConversationContentStart = getResources().getDimensionPixelSize( R.dimen.conversation_content_start); mInternalButtonPadding Loading Loading @@ -354,7 +357,6 @@ public class ConversationLayout extends FrameLayout // mUser now set (would be nice to avoid the side effect but WHATEVER) setUser(extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON)); // Append remote input history to newMessages (again, side effect is lame but WHATEVS) RemoteInputHistoryItem[] history = (RemoteInputHistoryItem[]) extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS); Loading @@ -362,9 +364,11 @@ public class ConversationLayout extends FrameLayout boolean showSpinner = extras.getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false); // bind it, baby bind(newMessages, newHistoricMessages, showSpinner); int unreadCount = extras.getInt(Notification.EXTRA_CONVERSATION_UNREAD_MESSAGE_COUNT); setUnreadCount(unreadCount); } @Override Loading @@ -372,6 +376,18 @@ public class ConversationLayout extends FrameLayout mImageResolver = resolver; } /** @hide */ public void setUnreadCount(int unreadCount) { mUnreadBadge.setVisibility(mIsCollapsed && unreadCount > 1 ? VISIBLE : GONE); CharSequence text = unreadCount >= 100 ? getResources().getString(R.string.unread_convo_overflow, 99) : String.format(Locale.getDefault(), "%d", unreadCount); mUnreadBadge.setText(text); mUnreadBadge.setBackgroundTintList(ColorStateList.valueOf(mLayoutColor)); boolean needDarkText = ColorUtils.calculateLuminance(mLayoutColor) > 0.5f; mUnreadBadge.setTextColor(needDarkText ? Color.BLACK : Color.WHITE); } private void addRemoteInputHistoryToMessages( List<Notification.MessagingStyle.Message> newMessages, RemoteInputHistoryItem[] remoteInputHistory) { Loading
core/res/res/drawable/conversation_unread_bg.xml 0 → 100644 +19 −0 Original line number Diff line number Diff line <!-- ~ Copyright (C) 2020 The Android Open Source Project ~ ~ Licensed under the Apache License, Version 2.0 (the "License"); ~ you may not use this file except in compliance with the License. ~ You may obtain a copy of the License at ~ ~ http://www.apache.org/licenses/LICENSE-2.0 ~ ~ Unless required by applicable law or agreed to in writing, software ~ distributed under the License is distributed on an "AS IS" BASIS, ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ~ See the License for the specific language governing permissions and ~ limitations under the License. --> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <corners android:radius="20sp" /> <solid android:color="@android:color/white" /> </shape> No newline at end of file
core/res/res/layout/notification_template_material_conversation.xml +17 −4 Original line number Diff line number Diff line Loading @@ -199,10 +199,8 @@ android:clipChildren="false" /> </com.android.internal.widget.RemeasuringLinearLayout> <!-- Unread Count --> <!-- <TextView /> --> <!-- This is where the expand button will be placed when collapsed--> <!-- This is where the expand button container will be placed when collapsed--> </com.android.internal.widget.RemeasuringLinearLayout> <include layout="@layout/notification_template_smart_reply_container" Loading Loading @@ -238,6 +236,21 @@ android:clipToPadding="false" android:clipChildren="false" /> <!-- Unread Count --> <TextView android:id="@+id/conversation_unread_count" android:layout_width="33sp" android:layout_height="wrap_content" android:layout_marginEnd="11dp" android:layout_gravity="center" android:gravity="center" android:padding="2dp" android:visibility="gone" android:textAppearance="@style/TextAppearance.DeviceDefault.Notification" android:textColor="#FFFFFF" android:textSize="12sp" android:background="@drawable/conversation_unread_bg" /> <com.android.internal.widget.NotificationExpandButton android:id="@+id/expand_button" android:layout_width="@dimen/notification_header_expand_icon_size" Loading
core/res/res/values/strings.xml +3 −0 Original line number Diff line number Diff line Loading @@ -5442,6 +5442,9 @@ <!-- Conversation Title fallback if the there is no name provided in a group chat conversation [CHAR LIMIT=40]--> <string name="conversation_title_fallback_group_chat">Group Conversation</string> <!-- Number of unread messages displayed on a conversation notification, when greater-than-or-equal-to 100 [CHAR LIMIT=3]--> <string name="unread_convo_overflow"><xliff:g id="max_unread_count" example="99">%1$d</xliff:g>+</string> <!-- ResolverActivity - profile tabs --> <!-- Label of a tab on a screen. A user can tap this tap to switch to the 'Personal' view (that shows their personal content) if they have a work profile on their device. [CHAR LIMIT=NONE] --> <string name="resolver_personal_tab">Personal</string> Loading