summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Julia Reynolds <juliacr@google.com> 2025-01-27 05:54:40 -0800
committer Android (Google) Code Review <android-gerrit@google.com> 2025-01-27 05:54:40 -0800
commit24109ce09d293ae06fb9a84654c42b8d940fd3cf (patch)
tree6e27302ef61c8a7b0c104ffadfcd2dd62a8f5012
parent70e09e957b85b7aa7d12b67dd3a9ba42de1d9900 (diff)
parent4008c23cf635a5ee17209c89ebbb70da7ac1906f (diff)
Merge changes Ib7ba44e3,Id1a5b8ec into main
* changes: Show summary in single line hybrid view Show summarized text, if any, in msg collapsed view
-rw-r--r--core/java/android/app/Notification.java5
-rw-r--r--core/java/com/android/internal/widget/ConversationLayout.java29
-rw-r--r--core/java/com/android/internal/widget/MessagingData.java13
-rw-r--r--core/java/com/android/internal/widget/MessagingMessage.java2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt39
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NmSummarizationUiFlag.kt50
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustment.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/SingleLineViewBinder.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/SingleLineViewModel.kt1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt70
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflaterTest.kt32
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java3
18 files changed, 270 insertions, 17 deletions
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 35308ee43dea..40db6dd1b0ba 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1772,6 +1772,11 @@ public class Notification implements Parcelable
*/
public static final String EXTRA_FOREGROUND_APPS = "android.foregroundApps";
+ /**
+ * @hide
+ */
+ public static final String EXTRA_SUMMARIZED_CONTENT = "android.summarization";
+
@UnsupportedAppUsage
private Icon mSmallIcon;
@UnsupportedAppUsage
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index b3ab5d3cd258..04ce9bcd7afd 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -105,6 +105,7 @@ public class ConversationLayout extends FrameLayout
private ArrayList<MessagingGroup> mAddedGroups = new ArrayList<>();
private Person mUser;
private CharSequence mNameReplacement;
+ private CharSequence mSummarizedContent;
private boolean mIsCollapsed;
private ImageResolver mImageResolver;
private CachingIconView mConversationIconView;
@@ -397,7 +398,7 @@ public class ConversationLayout extends FrameLayout
*
* @param isCollapsed is it collapsed
*/
- @RemotableViewMethod
+ @RemotableViewMethod(asyncImpl = "setIsCollapsedAsync")
public void setIsCollapsed(boolean isCollapsed) {
mIsCollapsed = isCollapsed;
mMessagingLinearLayout.setMaxDisplayedLines(isCollapsed ? 1 : Integer.MAX_VALUE);
@@ -406,6 +407,15 @@ public class ConversationLayout extends FrameLayout
}
/**
+ * setDataAsync needs to do different stuff for the collapsed vs expanded view, so store the
+ * collapsed state early.
+ */
+ public Runnable setIsCollapsedAsync(boolean isCollapsed) {
+ mIsCollapsed = isCollapsed;
+ return () -> setIsCollapsed(isCollapsed);
+ }
+
+ /**
* Set conversation data
*
* @param extras Bundle contains conversation data
@@ -439,8 +449,16 @@ public class ConversationLayout extends FrameLayout
extras.getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false);
int unreadCount = extras.getInt(Notification.EXTRA_CONVERSATION_UNREAD_MESSAGE_COUNT);
- final List<MessagingMessage> newMessagingMessages =
- createMessages(newMessages, /* isHistoric= */false, usePrecomputedText);
+ List<MessagingMessage> newMessagingMessages;
+ mSummarizedContent = extras.getCharSequence(Notification.EXTRA_SUMMARIZED_CONTENT);
+ if (mSummarizedContent != null && mIsCollapsed) {
+ Notification.MessagingStyle.Message summary =
+ new Notification.MessagingStyle.Message(mSummarizedContent, 0, "");
+ newMessagingMessages = createMessages(List.of(summary), false, usePrecomputedText);
+ } else {
+ newMessagingMessages =
+ createMessages(newMessages, /* isHistoric= */false, usePrecomputedText);
+ }
final List<MessagingMessage> newHistoricMessagingMessages =
createMessages(newHistoricMessages, /* isHistoric= */true, usePrecomputedText);
@@ -463,7 +481,7 @@ public class ConversationLayout extends FrameLayout
return new MessagingData(user, showSpinner, unreadCount,
newHistoricMessagingMessages, newMessagingMessages, groups, senders,
- conversationHeaderData);
+ conversationHeaderData, mSummarizedContent);
}
/**
@@ -1622,6 +1640,9 @@ public class ConversationLayout extends FrameLayout
@Nullable
public CharSequence getConversationText() {
+ if (mSummarizedContent != null) {
+ return mSummarizedContent;
+ }
if (mMessages.isEmpty()) {
return null;
}
diff --git a/core/java/com/android/internal/widget/MessagingData.java b/core/java/com/android/internal/widget/MessagingData.java
index fb1f28fb8ef3..cb5041efd10f 100644
--- a/core/java/com/android/internal/widget/MessagingData.java
+++ b/core/java/com/android/internal/widget/MessagingData.java
@@ -32,6 +32,7 @@ final class MessagingData {
private final List<List<MessagingMessage>> mGroups;
private final List<Person> mSenders;
private final int mUnreadCount;
+ private final CharSequence mSummarization;
private ConversationHeaderData mConversationHeaderData;
@@ -41,8 +42,7 @@ final class MessagingData {
List<Person> senders) {
this(user, showSpinner, /* unreadCount= */0,
historicMessagingMessages, newMessagingMessages,
- groups,
- senders, null);
+ groups, senders, null, null);
}
MessagingData(Person user, boolean showSpinner,
@@ -51,7 +51,8 @@ final class MessagingData {
List<MessagingMessage> newMessagingMessages,
List<List<MessagingMessage>> groups,
List<Person> senders,
- @Nullable ConversationHeaderData conversationHeaderData) {
+ @Nullable ConversationHeaderData conversationHeaderData,
+ CharSequence summarization) {
mUser = user;
mShowSpinner = showSpinner;
mUnreadCount = unreadCount;
@@ -60,6 +61,7 @@ final class MessagingData {
mGroups = groups;
mSenders = senders;
mConversationHeaderData = conversationHeaderData;
+ mSummarization = summarization;
}
public Person getUser() {
@@ -94,4 +96,9 @@ final class MessagingData {
public ConversationHeaderData getConversationHeaderData() {
return mConversationHeaderData;
}
+
+ @Nullable
+ public CharSequence getSummarization() {
+ return mSummarization;
+ }
}
diff --git a/core/java/com/android/internal/widget/MessagingMessage.java b/core/java/com/android/internal/widget/MessagingMessage.java
index a59ee77cc693..c7f22836dd93 100644
--- a/core/java/com/android/internal/widget/MessagingMessage.java
+++ b/core/java/com/android/internal/widget/MessagingMessage.java
@@ -24,7 +24,7 @@ import java.util.ArrayList;
import java.util.Objects;
/**
- * A message of a {@link MessagingLayout}.
+ * A message or summary of a {@link MessagingLayout}.
*/
public interface MessagingMessage extends MessagingLinearLayout.MessagingChild {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt
index 3c772fdbe0b2..356eedbc9a45 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt
@@ -29,6 +29,7 @@ import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_NONE
import com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_PUBLIC
+import com.android.systemui.statusbar.RankingBuilder
import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
@@ -242,4 +243,42 @@ class NotifUiAdjustmentProviderTest : SysuiTestCase() {
// Then: need no re-inflation
assertFalse(NotifUiAdjustment.needReinflate(oldAdjustment, newAdjustment))
}
+
+ @Test
+ @EnableFlags(android.app.Flags.FLAG_NM_SUMMARIZATION_UI)
+ fun changeIsSummarization_needReInflation_newlySummarized() {
+ // Given: an Entry with no summarization
+ val oldAdjustment = adjustmentProvider.calculateAdjustment(entry)
+ assertThat(oldAdjustment.summarization).isNull()
+
+ // When: the Entry now has a summarization
+ val rb = RankingBuilder(entry.ranking)
+ rb.setSummarization("summary!")
+ entry.ranking = rb.build()
+ val newAdjustment = adjustmentProvider.calculateAdjustment(entry)
+ assertThat(newAdjustment).isNotEqualTo(oldAdjustment)
+
+ // Then: Need re-inflation
+ assertTrue(NotifUiAdjustment.needReinflate(oldAdjustment, newAdjustment))
+ }
+
+ @Test
+ @EnableFlags(android.app.Flags.FLAG_NM_SUMMARIZATION_UI)
+ fun changeIsSummarization_needReInflation_summarizationChanged() {
+ // Given: an Entry with no summarization
+ val rb = RankingBuilder(entry.ranking)
+ rb.setSummarization("summary!")
+ entry.ranking = rb.build()
+ val oldAdjustment = adjustmentProvider.calculateAdjustment(entry)
+
+ // When: the Entry now has a new summarization
+ val rb2 = RankingBuilder(entry.ranking)
+ rb2.setSummarization("summary new!")
+ entry.ranking = rb2.build()
+ val newAdjustment = adjustmentProvider.calculateAdjustment(entry)
+ assertThat(newAdjustment).isNotEqualTo(oldAdjustment)
+
+ // Then: Need re-inflation
+ assertTrue(NotifUiAdjustment.needReinflate(oldAdjustment, newAdjustment))
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
index 3825c098ca5d..b6ef95893036 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification
import android.app.Notification
+import android.app.Notification.EXTRA_SUMMARIZED_CONTENT
import android.content.Context
import android.content.pm.LauncherApps
import android.graphics.drawable.AnimatedImageDrawable
@@ -66,6 +67,12 @@ constructor(
messagingStyle.shortcutIcon = launcherApps.getShortcutIcon(shortcutInfo)
shortcutInfo.label?.let { label -> messagingStyle.conversationTitle = label }
}
+ if (NmSummarizationUiFlag.isEnabled) {
+ entry.sbn.notification.extras.putCharSequence(
+ EXTRA_SUMMARIZED_CONTENT, entry.ranking.summarization
+ )
+ }
+
messagingStyle.unreadMessageCount =
conversationNotificationManager.getUnreadCount(entry, recoveredBuilder)
return messagingStyle
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NmSummarizationUiFlag.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NmSummarizationUiFlag.kt
new file mode 100644
index 000000000000..feac0a514828
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NmSummarizationUiFlag.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2025 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.
+ */
+package com.android.systemui.statusbar.notification
+
+import android.app.Flags;
+import com.android.systemui.flags.FlagToken
+import com.android.systemui.flags.RefactorFlagUtils
+
+/**
+ * Helper for android.app.nm_summarization and android.nm_summarization_ui. The new functionality
+ * should be enabled if either flag is enabled.
+ */
+@Suppress("NOTHING_TO_INLINE")
+object NmSummarizationUiFlag {
+ const val FLAG_DESC = "android.app.nm_summarization(_ui)"
+
+ @JvmStatic
+ inline val isEnabled
+ get() = Flags.nmSummarizationUi() || Flags.nmSummarization()
+
+ /**
+ * Called to ensure code is only run when the flag is enabled. This protects users from the
+ * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
+ * build to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun isUnexpectedlyInLegacyMode() =
+ RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_DESC)
+
+ /**
+ * Called to ensure code is only run when the flag is disabled. This will throw an exception if
+ * the flag is enabled to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun assertInLegacyMode() =
+ RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_DESC)
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustment.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustment.kt
index 331ef1c01596..aa5008b8416e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustment.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustment.kt
@@ -40,6 +40,7 @@ internal constructor(
@RedactionType val redactionType: Int,
val isChildInGroup: Boolean,
val isGroupSummary: Boolean,
+ val summarization: String?,
) {
companion object {
@JvmStatic
@@ -61,6 +62,7 @@ internal constructor(
AsyncGroupHeaderViewInflation.isEnabled &&
!oldAdjustment.isGroupSummary &&
newAdjustment.isGroupSummary -> true
+ oldAdjustment.summarization != newAdjustment.summarization -> true
else -> false
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt
index 97e55c19d2f4..465bc288cbc1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt
@@ -152,5 +152,6 @@ constructor(
},
isChildInGroup = entry.hasEverBeenGroupChild(),
isGroupSummary = entry.hasEverBeenGroupSummary(),
+ summarization = entry.ranking.summarization
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java
index 1ff0d9262476..92c10abff735 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java
@@ -288,14 +288,21 @@ public class HybridConversationNotificationView extends HybridNotificationView {
public void setText(
CharSequence titleText,
CharSequence contentText,
- CharSequence conversationSenderName
+ CharSequence conversationSenderName,
+ @Nullable String summarization
) {
if (AsyncHybridViewInflation.isUnexpectedlyInLegacyMode()) return;
- if (conversationSenderName == null) {
+ if (summarization != null) {
mConversationSenderName.setVisibility(GONE);
+ titleText = null;
+ contentText = summarization;
} else {
- mConversationSenderName.setVisibility(VISIBLE);
- mConversationSenderName.setText(conversationSenderName);
+ if (conversationSenderName == null) {
+ mConversationSenderName.setVisibility(GONE);
+ } else {
+ mConversationSenderName.setVisibility(VISIBLE);
+ mConversationSenderName.setText(conversationSenderName);
+ }
}
// TODO (b/217799515): super.bind() doesn't use contentView, remove the contentView
// argument when the flag is removed
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index c0dbb37c1b36..13ed6c449797 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -217,7 +217,8 @@ public class NotificationContentInflater implements NotificationRowContentBinder
messagingStyle,
builder,
row.getContext(),
- false
+ false,
+ entry.getRanking().getSummarization()
);
// If the messagingStyle is null, we want to inflate the normal view
isConversation = viewModel.isConversation();
@@ -239,7 +240,8 @@ public class NotificationContentInflater implements NotificationRowContentBinder
messagingStyle,
builder,
row.getContext(),
- true);
+ true,
+ entry.getRanking().getSummarization());
} else {
result.mPublicInflatedSingleLineViewModel =
SingleLineViewInflater.inflateRedactedSingleLineViewModel(
@@ -1318,7 +1320,8 @@ public class NotificationContentInflater implements NotificationRowContentBinder
messagingStyle,
recoveredBuilder,
mContext,
- false
+ false,
+ mEntry.getRanking().getSummarization()
);
result.mInflatedSingleLineView =
SingleLineViewInflater.inflatePrivateSingleLineView(
@@ -1338,7 +1341,8 @@ public class NotificationContentInflater implements NotificationRowContentBinder
messagingStyle,
recoveredBuilder,
mContext,
- true
+ true,
+ null
);
} else {
result.mPublicInflatedSingleLineViewModel =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
index 0b299d965b09..f4aae6e288a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
@@ -719,6 +719,7 @@ constructor(
builder = builder,
systemUiContext = systemUiContext,
redactText = false,
+ summarization = entry.ranking.summarization
)
} else null
@@ -735,6 +736,7 @@ constructor(
builder = builder,
systemUiContext = systemUiContext,
redactText = true,
+ summarization = null
)
} else {
SingleLineViewInflater.inflateRedactedSingleLineViewModel(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt
index fe2803bfc5d6..c051513ef3b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt
@@ -61,6 +61,7 @@ internal object SingleLineViewInflater {
builder: Notification.Builder,
systemUiContext: Context,
redactText: Boolean,
+ summarization: String?
): SingleLineViewModel {
if (AsyncHybridViewInflation.isUnexpectedlyInLegacyMode()) {
return SingleLineViewModel(null, null, null)
@@ -108,6 +109,7 @@ internal object SingleLineViewInflater {
conversationSenderName =
if (isGroupConversation) conversationTextData?.senderName else null,
avatar = conversationAvatar,
+ summarization = summarization
)
return SingleLineViewModel(
@@ -132,6 +134,7 @@ internal object SingleLineViewInflater {
.ic_redacted_notification_single_line_icon
)
),
+ null
)
} else {
null
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/SingleLineViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/SingleLineViewBinder.kt
index a17197c1f8ea..a50fc4c7986a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/SingleLineViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/SingleLineViewBinder.kt
@@ -32,6 +32,7 @@ object SingleLineViewBinder {
viewModel?.titleText,
viewModel?.contentText,
viewModel?.conversationData?.conversationSenderName,
+ viewModel?.conversationData?.summarization
)
} else {
// bind the title and content text views
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/SingleLineViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/SingleLineViewModel.kt
index d583fa5d97ed..32ded25f18a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/SingleLineViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/SingleLineViewModel.kt
@@ -46,6 +46,7 @@ data class SingleLineViewModel(
data class ConversationData(
val conversationSenderName: CharSequence?,
val avatar: ConversationAvatar,
+ val summarization: String?
)
/**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt
index 1eb88c5a5616..0457255fee4e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt
@@ -19,10 +19,12 @@ import android.app.Notification
import android.app.Person
import android.platform.test.annotations.EnableFlags
import android.testing.TestableLooper
+import android.view.View.GONE
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.RankingBuilder
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC_SINGLE_LINE
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_SINGLE_LINE
import com.android.systemui.statusbar.notification.row.SingleLineViewInflater.inflatePrivateSingleLineView
@@ -90,6 +92,7 @@ class SingleLineViewBinderTest : SysuiTestCase() {
builder = notificationBuilder,
systemUiContext = context,
redactText = false,
+ summarization = null
)
// WHEN: binds the viewHolder
@@ -151,6 +154,7 @@ class SingleLineViewBinderTest : SysuiTestCase() {
builder = notificationBuilder,
systemUiContext = context,
redactText = false,
+ summarization = null
)
// WHEN: binds the view
SingleLineViewBinder.bind(viewModel, view)
@@ -200,6 +204,7 @@ class SingleLineViewBinderTest : SysuiTestCase() {
builder = notificationBuilder,
systemUiContext = context,
redactText = false,
+ summarization = null
)
// WHEN: binds the view with the view model
SingleLineViewBinder.bind(viewModel, view)
@@ -211,6 +216,70 @@ class SingleLineViewBinderTest : SysuiTestCase() {
assertNull(viewModel.conversationData)
}
+ @Test
+ @EnableFlags(AsyncHybridViewInflation.FLAG_NAME, android.app.Flags.FLAG_NM_SUMMARIZATION_UI,
+ android.app.Flags.FLAG_NM_SUMMARIZATION)
+ fun bindSummarizedGroupConversationSingleLineView() {
+ // GIVEN a row with a group conversation notification
+ val user =
+ Person.Builder()
+ .setName(USER_NAME)
+ .build()
+ val style =
+ Notification.MessagingStyle(user)
+ .addMessage(MESSAGE_TEXT, System.currentTimeMillis(), user)
+ .addMessage(
+ "How about lunch?",
+ System.currentTimeMillis(),
+ Person.Builder().setName("user2").build(),
+ )
+ .setGroupConversation(true)
+ notificationBuilder.setStyle(style).setShortcutId(SHORTCUT_ID)
+ val notification = notificationBuilder.build()
+ val row = helper.createRow(notification)
+ val rb = RankingBuilder(row.entry.ranking)
+ rb.setSummarization("summary!")
+ row.entry.ranking = rb.build()
+
+ val view =
+ inflatePrivateSingleLineView(
+ isConversation = true,
+ reinflateFlags = FLAG_CONTENT_VIEW_SINGLE_LINE,
+ entry = row.entry,
+ context = context,
+ logger = mock(),
+ )
+ as HybridConversationNotificationView
+
+ val publicView =
+ inflatePublicSingleLineView(
+ isConversation = true,
+ reinflateFlags = FLAG_CONTENT_VIEW_PUBLIC_SINGLE_LINE,
+ entry = row.entry,
+ context = context,
+ logger = mock(),
+ )
+ as HybridConversationNotificationView
+ assertNotNull(publicView)
+
+ val viewModel =
+ SingleLineViewInflater.inflateSingleLineViewModel(
+ notification = notification,
+ messagingStyle = style,
+ builder = notificationBuilder,
+ systemUiContext = context,
+ redactText = false,
+ summarization = "summary"
+ )
+ // WHEN: binds the view
+ SingleLineViewBinder.bind(viewModel, view)
+
+ // THEN: the single-line conversation view should only include summarization content
+ assertEquals(viewModel.conversationData?.summarization, view.textView.text)
+ assertEquals("", view.conversationSenderNameView.text)
+ assertEquals(GONE, view.conversationSenderNameView.visibility)
+ }
+
private companion object {
const val CHANNEL_ID = "CHANNEL_ID"
const val CONTENT_TITLE = "A Cool New Feature"
@@ -218,5 +287,6 @@ class SingleLineViewBinderTest : SysuiTestCase() {
const val USER_NAME = "USER_NAME"
const val MESSAGE_TEXT = "MESSAGE_TEXT"
const val SHORTCUT_ID = "Shortcut"
+ const val SUMMARIZATION = "summarization"
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflaterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflaterTest.kt
index ef70e277832e..13724a8b44da 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflaterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflaterTest.kt
@@ -272,6 +272,35 @@ class SingleLineViewInflaterTest : SysuiTestCase() {
}
}
+ @Test
+ fun createViewModelForSummarizedConversationNotification() {
+ // Given: a non-group conversation notification
+ val notificationType = OneToOneConversation()
+ val notification = getNotification(notificationType)
+
+ // When: inflate the SingleLineViewModel
+ val singleLineViewModel = notification.makeSingleLineViewModel(notificationType)
+
+ // Then: the inflated SingleLineViewModel should be as expected
+ // titleText: Notification.ConversationTitle
+ // contentText: the last message text
+ // conversationSenderName: null, because it's not a group conversation
+ // conversationData.avatar: a single icon of the last sender
+ // summarizedText: the summary text from the ranking
+ assertEquals(CONVERSATION_TITLE, singleLineViewModel.titleText)
+ assertEquals(LAST_MESSAGE, singleLineViewModel.contentText)
+ assertNull(
+ singleLineViewModel.conversationData?.conversationSenderName,
+ "Sender name should be null for one-on-one conversation"
+ )
+ assertTrue {
+ singleLineViewModel.conversationData
+ ?.avatar
+ ?.equalsTo(SingleIcon(firstSenderIcon.loadDrawable(context))) == true
+ }
+ assertEquals("summary", singleLineViewModel.conversationData?.summarization)
+ }
+
sealed class NotificationType(val largeIcon: Icon? = null)
class NonMessaging(largeIcon: Icon? = null) : NotificationType(largeIcon)
@@ -380,7 +409,8 @@ class SingleLineViewInflaterTest : SysuiTestCase() {
if (isConversation) messagingStyle else null,
builder,
context,
- false
+ false,
+ "summary"
)
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 0d3c18ac339f..d19eb235c9d5 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -8505,6 +8505,9 @@ public class NotificationManagerService extends SystemService {
(userId == USER_ALL) ? USER_SYSTEM : userId);
Notification.addFieldsFromContext(ai, notification);
+ // can't be set by an app
+ notification.extras.remove(Notification.EXTRA_SUMMARIZED_CONTENT);
+
if (notification.isForegroundService() && fgsPolicy == NOT_FOREGROUND_SERVICE) {
notification.flags &= ~FLAG_FOREGROUND_SERVICE;
}