Merge "[Minimal HUN] - Apply Minimal HUN to Standard Notifications" into main
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 714454b..b19dc8f 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5709,6 +5709,7 @@
TemplateBindResult result) {
p.headerless(resId == getBaseLayoutResource()
|| resId == getHeadsUpBaseLayoutResource()
+ || resId == getCompactHeadsUpBaseLayoutResource()
|| resId == getMessagingLayoutResource()
|| resId == R.layout.notification_template_material_media);
RemoteViews contentView = new BuilderRemoteViews(mContext.getApplicationInfo(), resId);
@@ -6594,6 +6595,36 @@
}
/**
+ * Construct a RemoteViews for the final compact heads-up notification layout.
+ * @hide
+ */
+ public RemoteViews createCompactHeadsUpContentView() {
+ // TODO(b/336225281): re-evaluate custom view usage.
+ if (useExistingRemoteView(mN.headsUpContentView)) {
+ return fullyCustomViewRequiresDecoration(false /* fromStyle */)
+ ? minimallyDecoratedHeadsUpContentView(mN.headsUpContentView)
+ : mN.headsUpContentView;
+ } else if (mStyle != null) {
+ final RemoteViews styleView = mStyle.makeCompactHeadsUpContentView();
+ if (styleView != null) {
+ return styleView;
+ }
+ }
+
+ final StandardTemplateParams p = mParams.reset()
+ .viewType(StandardTemplateParams.VIEW_TYPE_HEADS_UP)
+ .fillTextsFrom(this);
+ // Notification text is shown as secondary header text
+ // for the minimal hun when it is provided.
+ // Time(when and chronometer) is not shown for the minimal hun.
+ p.headerTextSecondary(p.mText).text(null).hideTime(true);
+
+ return applyStandardTemplate(
+ getCompactHeadsUpBaseLayoutResource(), p,
+ null /* result */);
+ }
+
+ /**
* Construct a RemoteViews representing the heads up notification layout.
*
* @deprecated For performance and system health reasons, this API is no longer required to
@@ -7269,6 +7300,10 @@
return R.layout.notification_template_material_heads_up_base;
}
+ private int getCompactHeadsUpBaseLayoutResource() {
+ return R.layout.notification_template_material_compact_heads_up_base;
+ }
+
private int getBigBaseLayoutResource() {
return R.layout.notification_template_material_big_base;
}
@@ -7795,6 +7830,16 @@
}
/**
+ * Construct a Style-specific RemoteViews for the final compact HUN layout.
+ * return null to use the standard compact heads up view.
+ * @hide
+ */
+ @Nullable
+ public RemoteViews makeCompactHeadsUpContentView() {
+ return null;
+ }
+
+ /**
* Apply any style-specific extras to this notification before shipping it out.
* @hide
*/
@@ -9106,6 +9151,16 @@
/**
* @hide
*/
+ @Nullable
+ @Override
+ public RemoteViews makeCompactHeadsUpContentView() {
+ // TODO(b/336229954): Apply minimal HUN treatment to Messaging Notifications.
+ return makeHeadsUpContentView(false);
+ }
+
+ /**
+ * @hide
+ */
@Override
public void reduceImageSizes(Context context) {
super.reduceImageSizes(context);
@@ -10275,6 +10330,16 @@
/**
* @hide
*/
+ @Nullable
+ @Override
+ public RemoteViews makeCompactHeadsUpContentView() {
+ // TODO(b/336228700): Apply minimal HUN treatment for Call Style.
+ return makeHeadsUpContentView(false);
+ }
+
+ /**
+ * @hide
+ */
public RemoteViews makeBigContentView() {
return makeCallLayout(StandardTemplateParams.VIEW_TYPE_BIG);
}
diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig
index e694ccc..e3c367f8 100644
--- a/core/java/android/app/notification.aconfig
+++ b/core/java/android/app/notification.aconfig
@@ -138,4 +138,11 @@
namespace: "systemui"
description: "Cleans up spans and unnecessary new lines from standard notification templates"
bug: "313439845"
-}
\ No newline at end of file
+}
+
+flag {
+ name: "compact_heads_up_notification"
+ namespace: "systemui"
+ description: "[Minimal HUN] Enables the compact heads up notification feature"
+ bug: "270709257"
+}
diff --git a/core/res/res/layout/notification_template_material_compact_heads_up_base.xml b/core/res/res/layout/notification_template_material_compact_heads_up_base.xml
new file mode 100644
index 0000000..57da898
--- /dev/null
+++ b/core/res/res/layout/notification_template_material_compact_heads_up_base.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 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
+ -->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/status_bar_latest_event_content"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/notification_header_height"
+ android:clipChildren="false"
+ android:tag="compactHUN"
+ android:gravity="center_vertical"
+ android:theme="@style/Theme.DeviceDefault.Notification"
+ android:importantForAccessibility="no">
+ <com.android.internal.widget.CachingIconView
+ android:id="@+id/icon"
+ android:layout_width="@dimen/notification_icon_circle_size"
+ android:layout_height="@dimen/notification_icon_circle_size"
+ android:layout_gravity="center_vertical|start"
+ android:layout_marginStart="@dimen/notification_icon_circle_start"
+ android:background="@drawable/notification_icon_circle"
+ android:padding="@dimen/notification_icon_circle_padding"
+ android:maxDrawableWidth="@dimen/notification_icon_circle_size"
+ android:maxDrawableHeight="@dimen/notification_icon_circle_size"
+ />
+ <FrameLayout
+ android:id="@+id/alternate_expand_target"
+ android:layout_width="@dimen/notification_content_margin_start"
+ android:layout_height="match_parent"
+ android:layout_gravity="start"
+ android:importantForAccessibility="no"
+ android:focusable="false"
+ />
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginStart="@dimen/notification_content_margin_start"
+ android:orientation="horizontal"
+ >
+ <NotificationTopLineView
+ android:id="@+id/notification_top_line"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_centerVertical="true"
+ android:layout_weight="1"
+ android:clipChildren="false"
+ android:gravity="center_vertical"
+ android:theme="@style/Theme.DeviceDefault.Notification"
+ >
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/notification_header_separating_margin"
+ android:ellipsize="end"
+ android:fadingEdge="horizontal"
+ android:singleLine="true"
+ android:textAlignment="viewStart"
+ android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
+ />
+ <include layout="@layout/notification_top_line_views" />
+ </NotificationTopLineView>
+ <FrameLayout
+ android:id="@+id/expand_button_touch_container"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:minWidth="@dimen/notification_content_margin_end"
+ >
+ <include layout="@layout/notification_expand_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical|end"
+ />
+ </FrameLayout>
+ </LinearLayout>
+</FrameLayout>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 4f19c27..1e5c5d9 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2338,6 +2338,7 @@
<java-symbol type="layout" name="notification_material_action_tombstone" />
<java-symbol type="layout" name="notification_template_material_base" />
<java-symbol type="layout" name="notification_template_material_heads_up_base" />
+ <java-symbol type="layout" name="notification_template_material_compact_heads_up_base" />
<java-symbol type="layout" name="notification_template_material_big_base" />
<java-symbol type="layout" name="notification_template_material_big_picture" />
<java-symbol type="layout" name="notification_template_material_inbox" />
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HeadsUpStyleProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HeadsUpStyleProvider.kt
new file mode 100644
index 0000000..816e5c1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HeadsUpStyleProvider.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 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.row
+
+import android.app.Flags
+import javax.inject.Inject
+
+/**
+ * A class managing the heads up style to be applied based on user settings, immersive mode and
+ * other factors.
+ */
+interface HeadsUpStyleProvider {
+ fun shouldApplyCompactStyle(): Boolean
+}
+
+class HeadsUpStyleProviderImpl @Inject constructor() : HeadsUpStyleProvider {
+
+ /**
+ * TODO(b/270709257) This feature is under development. This method returns Compact when the
+ * flag is enabled for fish fooding purpose.
+ */
+ override fun shouldApplyCompactStyle(): Boolean = Flags.compactHeadsUpNotification()
+}
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 31e69c9..2f03871 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
@@ -90,6 +90,8 @@
private final Executor mInflationExecutor;
private final SmartReplyStateInflater mSmartReplyStateInflater;
private final NotifLayoutInflaterFactory.Provider mNotifLayoutInflaterFactoryProvider;
+ private final HeadsUpStyleProvider mHeadsUpStyleProvider;
+
private final NotificationContentInflaterLogger mLogger;
@Inject
@@ -101,6 +103,7 @@
@NotifInflation Executor inflationExecutor,
SmartReplyStateInflater smartRepliesInflater,
NotifLayoutInflaterFactory.Provider notifLayoutInflaterFactoryProvider,
+ HeadsUpStyleProvider headsUpStyleProvider,
NotificationContentInflaterLogger logger) {
mRemoteViewCache = remoteViewCache;
mRemoteInputManager = remoteInputManager;
@@ -109,6 +112,7 @@
mInflationExecutor = inflationExecutor;
mSmartReplyStateInflater = smartRepliesInflater;
mNotifLayoutInflaterFactoryProvider = notifLayoutInflaterFactoryProvider;
+ mHeadsUpStyleProvider = headsUpStyleProvider;
mLogger = logger;
}
@@ -158,6 +162,7 @@
/* isMediaFlagEnabled = */ mIsMediaInQS,
mSmartReplyStateInflater,
mNotifLayoutInflaterFactoryProvider,
+ mHeadsUpStyleProvider,
mLogger);
if (mInflateSynchronously) {
task.onPostExecute(task.doInBackground());
@@ -184,6 +189,7 @@
packageContext,
row,
mNotifLayoutInflaterFactoryProvider,
+ mHeadsUpStyleProvider,
mLogger);
result = inflateSmartReplyViews(result, reInflateFlags, entry, row.getContext(),
@@ -370,6 +376,7 @@
boolean usesIncreasedHeadsUpHeight, Context packageContext,
ExpandableNotificationRow row,
NotifLayoutInflaterFactory.Provider notifLayoutInflaterFactoryProvider,
+ HeadsUpStyleProvider headsUpStyleProvider,
NotificationContentInflaterLogger logger) {
return TraceUtils.trace("NotificationContentInflater.createRemoteViews", () -> {
InflationProgress result = new InflationProgress();
@@ -388,8 +395,13 @@
if ((reInflateFlags & FLAG_CONTENT_VIEW_HEADS_UP) != 0) {
logger.logAsyncTaskProgress(entryForLogging, "creating heads up remote view");
- result.newHeadsUpView = builder.createHeadsUpContentView(
- usesIncreasedHeadsUpHeight);
+ final boolean isHeadsUpCompact = headsUpStyleProvider.shouldApplyCompactStyle();
+ if (isHeadsUpCompact) {
+ result.newHeadsUpView = builder.createCompactHeadsUpContentView();
+ } else {
+ result.newHeadsUpView = builder.createHeadsUpContentView(
+ usesIncreasedHeadsUpHeight);
+ }
}
if ((reInflateFlags & FLAG_CONTENT_VIEW_PUBLIC) != 0) {
@@ -1067,6 +1079,7 @@
private final boolean mIsMediaInQS;
private final SmartReplyStateInflater mSmartRepliesInflater;
private final NotifLayoutInflaterFactory.Provider mNotifLayoutInflaterFactoryProvider;
+ private final HeadsUpStyleProvider mHeadsUpStyleProvider;
private final NotificationContentInflaterLogger mLogger;
private AsyncInflationTask(
@@ -1085,6 +1098,7 @@
boolean isMediaFlagEnabled,
SmartReplyStateInflater smartRepliesInflater,
NotifLayoutInflaterFactory.Provider notifLayoutInflaterFactoryProvider,
+ HeadsUpStyleProvider headsUpStyleProvider,
NotificationContentInflaterLogger logger) {
mEntry = entry;
mRow = row;
@@ -1102,6 +1116,7 @@
mConversationProcessor = conversationProcessor;
mIsMediaInQS = isMediaFlagEnabled;
mNotifLayoutInflaterFactoryProvider = notifLayoutInflaterFactoryProvider;
+ mHeadsUpStyleProvider = headsUpStyleProvider;
mLogger = logger;
entry.setInflationTask(this);
}
@@ -1166,7 +1181,7 @@
InflationProgress inflationProgress = createRemoteViews(mReInflateFlags,
recoveredBuilder, mIsMinimized, mUsesIncreasedHeight,
mUsesIncreasedHeadsUpHeight, packageContext, mRow,
- mNotifLayoutInflaterFactoryProvider, mLogger);
+ mNotifLayoutInflaterFactoryProvider, mHeadsUpStyleProvider, mLogger);
mLogger.logAsyncTaskProgress(mEntry,
"getting existing smart reply state (on wrong thread!)");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java
index 200a08a..17c2026 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java
@@ -50,4 +50,12 @@
@SysUISingleton
public abstract NotifRemoteViewsFactoryContainer provideNotifRemoteViewsFactoryContainer(
NotifRemoteViewsFactoryContainerImpl containerImpl);
+
+ /**
+ * Provides heads up style manager
+ */
+ @Binds
+ @SysUISingleton
+ public abstract HeadsUpStyleProvider provideHeadsUpStyleManager(
+ HeadsUpStyleProviderImpl headsUpStyleManagerImpl);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCompactHeadsUpTemplateViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCompactHeadsUpTemplateViewWrapper.kt
new file mode 100644
index 0000000..ce87d2f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCompactHeadsUpTemplateViewWrapper.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2024 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.row.wrapper
+
+import android.content.Context
+import android.view.View
+import com.android.systemui.statusbar.notification.FeedbackIcon
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+
+/**
+ * Compact Heads up Notifications template that doesn't set feedback icon and audibly alert icons
+ */
+class NotificationCompactHeadsUpTemplateViewWrapper(
+ ctx: Context,
+ view: View,
+ row: ExpandableNotificationRow
+) : NotificationTemplateViewWrapper(ctx, view, row) {
+ override fun setFeedbackIcon(icon: FeedbackIcon?) = Unit
+ override fun setRecentlyAudiblyAlerted(audiblyAlerted: Boolean) = Unit
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
index 50f3e78..4244542 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
@@ -72,7 +72,10 @@
return new NotificationConversationTemplateViewWrapper(ctx, v, row);
} else if ("call".equals(v.getTag())) {
return new NotificationCallTemplateViewWrapper(ctx, v, row);
+ } else if ("compactHUN".equals((v.getTag()))) {
+ return new NotificationCompactHeadsUpTemplateViewWrapper(ctx, v, row);
}
+
if (row.getEntry().getSbn().getNotification().isStyle(
Notification.DecoratedCustomViewStyle.class)) {
return new NotificationDecoratedCustomViewWrapper(ctx, v, row);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
index 8c22511..03a8403 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
@@ -95,6 +95,7 @@
@Mock private InflatedSmartReplyState mInflatedSmartReplyState;
@Mock private InflatedSmartReplyViewHolder mInflatedSmartReplies;
@Mock private NotifLayoutInflaterFactory.Provider mNotifLayoutInflaterFactoryProvider;
+ @Mock private HeadsUpStyleProvider mHeadsUpStyleProvider;
@Mock private NotifLayoutInflaterFactory mNotifLayoutInflaterFactory;
private final SmartReplyStateInflater mSmartReplyStateInflater =
@@ -138,6 +139,7 @@
mock(Executor.class),
mSmartReplyStateInflater,
mNotifLayoutInflaterFactoryProvider,
+ mHeadsUpStyleProvider,
mock(NotificationContentInflaterLogger.class));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index 954335e..f35ec74 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -199,6 +199,7 @@
mock(Executor.class),
new MockSmartReplyInflater(),
mock(NotifLayoutInflaterFactory.Provider.class),
+ mock(HeadsUpStyleProvider.class),
mock(NotificationContentInflaterLogger.class));
contentBinder.setInflateSynchronously(true);
mBindStage = new RowContentBindStage(contentBinder,