Merge "Update the autogroup summary icon on notification changes" into main
diff --git a/core/res/res/drawable/ic_notification_summary_auto.xml b/core/res/res/drawable/ic_notification_summary_auto.xml
new file mode 100644
index 0000000..908bba8
--- /dev/null
+++ b/core/res/res/drawable/ic_notification_summary_auto.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="960"
+ android:viewportHeight="960"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M260,760Q236,760 218,742Q200,724 200,700L200,140Q200,116 218,98Q236,80 260,80L820,80Q844,80 862,98Q880,116 880,140L880,700Q880,724 862,742Q844,760 820,760L260,760ZM260,700L820,700Q820,700 820,700Q820,700 820,700L820,140Q820,140 820,140Q820,140 820,140L260,140Q260,140 260,140Q260,140 260,140L260,700Q260,700 260,700Q260,700 260,700ZM140,880Q116,880 98,862Q80,844 80,820L80,200L140,200L140,820Q140,820 140,820Q140,820 140,820L760,820L760,880L140,880ZM260,140L260,140Q260,140 260,140Q260,140 260,140L260,700Q260,700 260,700Q260,700 260,700L260,700Q260,700 260,700Q260,700 260,700L260,140Q260,140 260,140Q260,140 260,140Z"/>
+</vector>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b8a399b..4cf37df 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3146,6 +3146,7 @@
<java-symbol type="drawable" name="ic_collapse_notification" />
<java-symbol type="drawable" name="ic_expand_bundle" />
<java-symbol type="drawable" name="ic_collapse_bundle" />
+ <java-symbol type="drawable" name="ic_notification_summary_auto" />
<java-symbol type="dimen" name="notification_header_shrink_min_width" />
<java-symbol type="dimen" name="notification_header_shrink_hide_width" />
<java-symbol type="dimen" name="notification_content_margin_start" />
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 1b25d7f..ee1a4ac 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -66,6 +66,7 @@
"android.view.accessibility.flags-aconfig-java",
"androidx.core_core",
"androidx.core_core-ktx",
+ "androidx.test.core",
"androidx.test.espresso.core",
"androidx.test.ext.junit",
"androidx.test.runner",
@@ -90,6 +91,7 @@
"flickerlib-parsers",
"flickerlib-trace_processor_shell",
"mockito-target-extended-minus-junit4",
+ "TestParameterInjector",
],
libs: [
diff --git a/core/tests/coretests/res/drawable/adaptiveicon_drawable.xml b/core/tests/coretests/res/drawable/adaptiveicon_drawable.xml
new file mode 100644
index 0000000..dcffe75
--- /dev/null
+++ b/core/tests/coretests/res/drawable/adaptiveicon_drawable.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2023 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.
+ -->
+
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@android:color/white"/>
+ <foreground android:drawable="@android:color/black"/>
+ <monochrome android:drawable="@android:color/system_accent2_800"/>
+</adaptive-icon>
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/graphics/drawable/IconTest.java b/core/tests/coretests/src/android/graphics/drawable/IconTest.java
index 49ed3a8..950925f 100644
--- a/core/tests/coretests/src/android/graphics/drawable/IconTest.java
+++ b/core/tests/coretests/src/android/graphics/drawable/IconTest.java
@@ -18,8 +18,13 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
import android.app.IUriGrantsManager;
import android.content.ContentProvider;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.ParceledListSlice;
import android.graphics.Bitmap;
@@ -32,13 +37,15 @@
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
-import android.test.AndroidTestCase;
import android.util.Log;
-import androidx.test.filters.SmallTest;
+import androidx.test.core.app.ApplicationProvider;
import com.android.frameworks.coretests.R;
+import com.google.testing.junit.testparameterinjector.TestParameter;
+import com.google.testing.junit.testparameterinjector.TestParameterInjector;
+
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
@@ -46,13 +53,29 @@
import java.util.ArrayList;
import java.util.Arrays;
-public class IconTest extends AndroidTestCase {
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(TestParameterInjector.class)
+public class IconTest {
public static final String TAG = IconTest.class.getSimpleName();
+ private Context mContext;
+
public static void L(String s, Object... parts) {
Log.d(TAG, (parts.length == 0) ? s : String.format(s, parts));
}
- @SmallTest
+ private Context getContext() {
+ return mContext;
+ }
+
+ @Before
+ public void setup() {
+ mContext = ApplicationProvider.getApplicationContext();
+ }
+
+ @Test
public void testWithBitmap() throws Exception {
final Bitmap bm1 = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888);
final Bitmap bm2 = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565);
@@ -119,7 +142,7 @@
}
}
- @SmallTest
+ @Test
public void testScaleDownIfNecessary() throws Exception {
final Bitmap bm = Bitmap.createBitmap(4321, 78, Bitmap.Config.ARGB_8888);
final Icon ic = Icon.createWithBitmap(bm);
@@ -132,7 +155,7 @@
assertThat(ic.getBitmap().getHeight()).isLessThan(21);
}
- @SmallTest
+ @Test
public void testWithAdaptiveBitmap() throws Exception {
final Bitmap bm1 = Bitmap.createBitmap(150, 150, Bitmap.Config.ARGB_8888);
@@ -166,7 +189,7 @@
}
}
- @SmallTest
+ @Test
public void testWithBitmapResource() throws Exception {
final Bitmap res1 = ((BitmapDrawable) getContext().getDrawable(R.drawable.landscape))
.getBitmap();
@@ -193,7 +216,7 @@
* Icon resource test that ensures we can load and draw non-bitmaps. (In this case,
* stat_sys_adb is assumed, and asserted, to be a vector drawable.)
*/
- @SmallTest
+ @Test
public void testWithStatSysAdbResource() throws Exception {
// establish reference bitmap
final float dp = getContext().getResources().getDisplayMetrics().density;
@@ -244,7 +267,7 @@
}
}
- @SmallTest
+ @Test
public void testWithFile() throws Exception {
final Bitmap bit1 = ((BitmapDrawable) getContext().getDrawable(R.drawable.landscape))
.getBitmap();
@@ -268,7 +291,55 @@
}
}
- @SmallTest
+ @Test
+ public void testWithAdaptiveIconResource_useMonochrome() throws Exception {
+ final int colorMono = ((ColorDrawable) getContext().getDrawable(
+ android.R.color.system_accent2_800)).getColor();
+ final Icon im1 = Icon.createWithResourceAdaptiveDrawable(getContext().getPackageName(),
+ R.drawable.adaptiveicon_drawable, true, 0.0f);
+ final Drawable draw1 = im1.loadDrawable(mContext);
+ assertThat(draw1 instanceof InsetDrawable).isTrue();
+ ColorDrawable colorDrawable = (ColorDrawable) ((DrawableWrapper) draw1).getDrawable();
+ assertThat(colorDrawable.getColor()).isEqualTo(colorMono);
+ }
+
+ @Test
+ public void testWithAdaptiveIconResource_dontUseMonochrome() throws Exception {
+ final int colorMono = ((ColorDrawable) getContext().getDrawable(
+ android.R.color.system_accent2_800)).getColor();
+ final int colorFg = ((ColorDrawable) getContext().getDrawable(
+ android.R.color.black)).getColor();
+ final int colorBg = ((ColorDrawable) getContext().getDrawable(
+ android.R.color.white)).getColor();
+
+ final Icon im1 = Icon.createWithResourceAdaptiveDrawable(getContext().getPackageName(),
+ R.drawable.adaptiveicon_drawable, false , 0.0f);
+ final Drawable draw1 = im1.loadDrawable(mContext);
+ assertThat(draw1 instanceof AdaptiveIconDrawable).isTrue();
+ ColorDrawable colorDrawableMono = (ColorDrawable) ((AdaptiveIconDrawable) draw1)
+ .getMonochrome();
+ assertThat(colorDrawableMono.getColor()).isEqualTo(colorMono);
+ ColorDrawable colorDrawableFg = (ColorDrawable) ((AdaptiveIconDrawable) draw1)
+ .getForeground();
+ assertThat(colorDrawableFg.getColor()).isEqualTo(colorFg);
+ ColorDrawable colorDrawableBg = (ColorDrawable) ((AdaptiveIconDrawable) draw1)
+ .getBackground();
+ assertThat(colorDrawableBg.getColor()).isEqualTo(colorBg);
+ }
+
+ @Test
+ public void testAdaptiveIconResource_sameAs(@TestParameter boolean useMonochrome)
+ throws Exception {
+ final Icon im1 = Icon.createWithResourceAdaptiveDrawable(getContext().getPackageName(),
+ R.drawable.adaptiveicon_drawable, useMonochrome, 1.0f);
+ final Parcel parcel = Parcel.obtain();
+ im1.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ final Icon im2 = Icon.CREATOR.createFromParcel(parcel);
+ assertThat(im1.sameAs(im2)).isTrue();
+ }
+
+ @Test
public void testAsync() throws Exception {
final Bitmap bit1 = ((BitmapDrawable) getContext().getDrawable(R.drawable.landscape))
.getBitmap();
@@ -311,7 +382,7 @@
L(TAG, "asyncTest: done");
}
- @SmallTest
+ @Test
public void testParcel() throws Exception {
final Bitmap originalbits = ((BitmapDrawable) getContext().getDrawable(R.drawable.landscape))
.getBitmap();
@@ -391,7 +462,7 @@
return (int) Math.sqrt(maxNumPixels / aspRatio);
}
- @SmallTest
+ @Test
public void testScaleDownMaxSizeWithBitmap() throws Exception {
final int bmpWidth = 13_000;
final int bmpHeight = 10_000;
@@ -408,7 +479,7 @@
assertThat(drawable.getIntrinsicHeight()).isEqualTo(maxHeight);
}
- @SmallTest
+ @Test
public void testScaleDownMaxSizeWithAdaptiveBitmap() throws Exception {
final int bmpWidth = 20_000;
final int bmpHeight = 10_000;
@@ -427,7 +498,7 @@
assertThat(drawable.getIntrinsicHeight()).isEqualTo(maxHeight);
}
- @SmallTest
+ @Test
public void testScaleDownMaxSizeWithResource() throws Exception {
final Icon ic = Icon.createWithResource(getContext(), R.drawable.test_too_big);
final BitmapDrawable drawable = (BitmapDrawable) ic.loadDrawable(mContext);
@@ -435,7 +506,7 @@
assertThat(drawable.getBitmap().getByteCount()).isAtMost(RecordingCanvas.MAX_BITMAP_SIZE);
}
- @SmallTest
+ @Test
public void testScaleDownMaxSizeWithFile() throws Exception {
final Bitmap bit1 = ((BitmapDrawable) getContext().getDrawable(R.drawable.test_too_big))
.getBitmap();
@@ -450,7 +521,7 @@
assertThat(drawable.getBitmap().getByteCount()).isAtMost(RecordingCanvas.MAX_BITMAP_SIZE);
}
- @SmallTest
+ @Test
public void testScaleDownMaxSizeWithData() throws Exception {
final int bmpBpp = 4;
final Bitmap originalBits = ((BitmapDrawable) getContext().getDrawable(
@@ -465,7 +536,7 @@
assertThat(drawable.getBitmap().getByteCount()).isAtMost(RecordingCanvas.MAX_BITMAP_SIZE);
}
- @SmallTest
+ @Test
public void testLoadSafeDrawable_loadSuccessful() throws FileNotFoundException {
int uid = 12345;
String packageName = "test_pkg";
@@ -509,7 +580,7 @@
}
}
- @SmallTest
+ @Test
public void testLoadSafeDrawable_grantRejected_nullDrawable() throws FileNotFoundException {
int uid = 12345;
String packageName = "test_pkg";
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index 45e29a8..f359025 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -154,6 +154,12 @@
// TYPE_DATA: data offset
private int mInt2;
+ // TYPE_RESOURCE: use the monochrome drawable from an AdaptiveIconDrawable
+ private boolean mUseMonochrome = false;
+
+ // TYPE_RESOURCE: wrap the monochrome drawable in an InsetDrawable with the specified inset
+ private float mInsetScale = 0.0f;
+
/**
* Gets the type of the icon provided.
* <p>
@@ -368,10 +374,34 @@
result.setTintList(mTintList);
result.setTintBlendMode(mBlendMode);
}
+
+ if (mUseMonochrome) {
+ return crateMonochromeDrawable(result, mInsetScale);
+ }
+
return result;
}
/**
+ * Gets the monochrome drawable from an {@link AdaptiveIconDrawable}.
+ *
+ * @param drawable An {@link AdaptiveIconDrawable}
+ * @return Adjusted (wrapped in {@link InsetDrawable}) monochrome drawable
+ * from an {@link AdaptiveIconDrawable}.
+ * Or the original drawable if no monochrome layer exists.
+ */
+ private static Drawable crateMonochromeDrawable(Drawable drawable, float inset) {
+ if (drawable instanceof AdaptiveIconDrawable) {
+ Drawable monochromeDrawable = ((AdaptiveIconDrawable) drawable).getMonochrome();
+ // wrap with negative inset => scale icon (inspired from BaseIconFactory)
+ if (monochromeDrawable != null) {
+ return new InsetDrawable(monochromeDrawable, inset);
+ }
+ }
+ return drawable;
+ }
+
+ /**
* Resizes image if size too large for Canvas to draw
* @param bitmap Bitmap to be resized if size > {@link RecordingCanvas.MAX_BITMAP_SIZE}
* @return resized bitmap
@@ -693,7 +723,9 @@
&& Arrays.equals(getDataBytes(), otherIcon.getDataBytes());
case TYPE_RESOURCE:
return getResId() == otherIcon.getResId()
- && Objects.equals(getResPackage(), otherIcon.getResPackage());
+ && Objects.equals(getResPackage(), otherIcon.getResPackage())
+ && mUseMonochrome == otherIcon.mUseMonochrome
+ && mInsetScale == otherIcon.mInsetScale;
case TYPE_URI:
case TYPE_URI_ADAPTIVE_BITMAP:
return Objects.equals(getUriString(), otherIcon.getUriString());
@@ -748,6 +780,26 @@
}
/**
+ * Create an Icon pointing to a drawable resource.
+ * @param resPackage Name of the package containing the resource in question
+ * @param resId ID of the drawable resource
+ * @param useMonochrome if this icon should use the monochrome res from the adaptive drawable
+ * @hide
+ */
+ public static @NonNull Icon createWithResourceAdaptiveDrawable(@NonNull String resPackage,
+ @DrawableRes int resId, boolean useMonochrome, float inset) {
+ if (resPackage == null) {
+ throw new IllegalArgumentException("Resource package name must not be null.");
+ }
+ final Icon rep = new Icon(TYPE_RESOURCE);
+ rep.mInt1 = resId;
+ rep.mUseMonochrome = useMonochrome;
+ rep.mInsetScale = inset;
+ rep.mString1 = resPackage;
+ return rep;
+ }
+
+ /**
* Create an Icon pointing to a bitmap in memory.
* @param bits A valid {@link android.graphics.Bitmap} object
*/
@@ -986,6 +1038,8 @@
final int resId = in.readInt();
mString1 = pkg;
mInt1 = resId;
+ mUseMonochrome = in.readBoolean();
+ mInsetScale = in.readFloat();
break;
case TYPE_DATA:
final int len = in.readInt();
@@ -1027,6 +1081,8 @@
case TYPE_RESOURCE:
dest.writeString(getResPackage());
dest.writeInt(getResId());
+ dest.writeBoolean(mUseMonochrome);
+ dest.writeFloat(mInsetScale);
break;
case TYPE_DATA:
dest.writeInt(getDataLength());
diff --git a/services/core/java/com/android/server/notification/GroupHelper.java b/services/core/java/com/android/server/notification/GroupHelper.java
index dff02bf..e349fa3 100644
--- a/services/core/java/com/android/server/notification/GroupHelper.java
+++ b/services/core/java/com/android/server/notification/GroupHelper.java
@@ -15,6 +15,7 @@
*/
package com.android.server.notification;
+import static android.app.Notification.COLOR_DEFAULT;
import static android.app.Notification.FLAG_AUTOGROUP_SUMMARY;
import static android.app.Notification.FLAG_AUTO_CANCEL;
import static android.app.Notification.FLAG_GROUP_SUMMARY;
@@ -23,15 +24,24 @@
import static android.app.Notification.FLAG_ONGOING_EVENT;
import android.annotation.NonNull;
+import android.app.Notification;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
import android.util.Slog;
+import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* NotificationManagerService helper for auto-grouping notifications.
@@ -41,6 +51,8 @@
protected static final String AUTOGROUP_KEY = "ranker_group";
+ protected static final int FLAG_INVALID = -1;
+
// Flags that all autogroup summaries have
protected static final int BASE_FLAGS =
FLAG_AUTOGROUP_SUMMARY | FLAG_GROUP_SUMMARY | FLAG_LOCAL_ONLY;
@@ -51,17 +63,22 @@
private final Callback mCallback;
private final int mAutoGroupAtCount;
+ private final Context mContext;
+ private final PackageManager mPackageManager;
// Only contains notifications that are not explicitly grouped by the app (aka no group or
// sort key).
// userId|packageName -> (keys of notifications that aren't in an explicit app group -> flags)
@GuardedBy("mUngroupedNotifications")
- private final ArrayMap<String, ArrayMap<String, Integer>> mUngroupedNotifications
+ private final ArrayMap<String, ArrayMap<String, NotificationAttributes>> mUngroupedNotifications
= new ArrayMap<>();
- public GroupHelper(int autoGroupAtCount, Callback callback) {
+ public GroupHelper(Context context, PackageManager packageManager, int autoGroupAtCount,
+ Callback callback) {
mAutoGroupAtCount = autoGroupAtCount;
mCallback = callback;
+ mContext = context;
+ mPackageManager = packageManager;
}
private String generatePackageKey(int userId, String pkg) {
@@ -70,15 +87,16 @@
@VisibleForTesting
@GuardedBy("mUngroupedNotifications")
- protected int getAutogroupSummaryFlags(@NonNull final ArrayMap<String, Integer> children) {
+ protected int getAutogroupSummaryFlags(
+ @NonNull final ArrayMap<String, NotificationAttributes> children) {
boolean allChildrenHasFlag = children.size() > 0;
int anyChildFlagSet = 0;
for (int i = 0; i < children.size(); i++) {
- if (!hasAnyFlag(children.valueAt(i), ALL_CHILDREN_FLAG)) {
+ if (!hasAnyFlag(children.valueAt(i).flags, ALL_CHILDREN_FLAG)) {
allChildrenHasFlag = false;
}
- if (hasAnyFlag(children.valueAt(i), ANY_CHILDREN_FLAGS)) {
- anyChildFlagSet |= (children.valueAt(i) & ANY_CHILDREN_FLAGS);
+ if (hasAnyFlag(children.valueAt(i).flags, ANY_CHILDREN_FLAGS)) {
+ anyChildFlagSet |= (children.valueAt(i).flags & ANY_CHILDREN_FLAGS);
}
}
return BASE_FLAGS | (allChildrenHasFlag ? ALL_CHILDREN_FLAG : 0) | anyChildFlagSet;
@@ -95,7 +113,6 @@
} else {
maybeUngroup(sbn, false, sbn.getUserId());
}
-
} catch (Exception e) {
Slog.e(TAG, "Failure processing new notification", e);
}
@@ -121,25 +138,47 @@
private void maybeGroup(StatusBarNotification sbn, boolean autogroupSummaryExists) {
int flags = 0;
List<String> notificationsToGroup = new ArrayList<>();
+ List<NotificationAttributes> childrenAttr = new ArrayList<>();
synchronized (mUngroupedNotifications) {
String key = generatePackageKey(sbn.getUserId(), sbn.getPackageName());
- final ArrayMap<String, Integer> children =
+ final ArrayMap<String, NotificationAttributes> children =
mUngroupedNotifications.getOrDefault(key, new ArrayMap<>());
- children.put(sbn.getKey(), sbn.getNotification().flags);
+ NotificationAttributes attr = new NotificationAttributes(sbn.getNotification().flags,
+ sbn.getNotification().getSmallIcon(), sbn.getNotification().color);
+ children.put(sbn.getKey(), attr);
mUngroupedNotifications.put(key, children);
if (children.size() >= mAutoGroupAtCount || autogroupSummaryExists) {
flags = getAutogroupSummaryFlags(children);
notificationsToGroup.addAll(children.keySet());
+ childrenAttr.addAll(children.values());
}
}
if (notificationsToGroup.size() > 0) {
if (autogroupSummaryExists) {
- mCallback.updateAutogroupSummary(sbn.getUserId(), sbn.getPackageName(), flags);
+ NotificationAttributes attr = new NotificationAttributes(flags,
+ sbn.getNotification().getSmallIcon(), sbn.getNotification().color);
+ if (Flags.autogroupSummaryIconUpdate()) {
+ attr = updateAutobundledSummaryIcon(sbn.getPackageName(), childrenAttr, attr);
+ }
+
+ mCallback.updateAutogroupSummary(sbn.getUserId(), sbn.getPackageName(), attr);
} else {
- mCallback.addAutoGroupSummary(
- sbn.getUserId(), sbn.getPackageName(), sbn.getKey(), flags);
+ Icon summaryIcon = sbn.getNotification().getSmallIcon();
+ int summaryIconColor = sbn.getNotification().color;
+ if (Flags.autogroupSummaryIconUpdate()) {
+ // Calculate the initial summary icon and icon color
+ NotificationAttributes iconAttr = getAutobundledSummaryIconAndColor(
+ sbn.getPackageName(), childrenAttr);
+ summaryIcon = iconAttr.icon;
+ summaryIconColor = iconAttr.iconColor;
+ }
+
+ NotificationAttributes attr = new NotificationAttributes(flags, summaryIcon,
+ summaryIconColor);
+ mCallback.addAutoGroupSummary(sbn.getUserId(), sbn.getPackageName(), sbn.getKey(),
+ attr);
}
for (String key : notificationsToGroup) {
mCallback.addAutoGroup(key);
@@ -154,16 +193,17 @@
* (b) if we need to remove our autogroup overlay for this notification
* (c) we need to remove the autogroup summary
*
- * And updates the internal state of un-app-grouped notifications and their flags
+ * And updates the internal state of un-app-grouped notifications and their flags.
*/
private void maybeUngroup(StatusBarNotification sbn, boolean notificationGone, int userId) {
boolean removeSummary = false;
- int summaryFlags = 0;
+ int summaryFlags = FLAG_INVALID;
boolean updateSummaryFlags = false;
boolean removeAutogroupOverlay = false;
+ List<NotificationAttributes> childrenAttrs = new ArrayList<>();
synchronized (mUngroupedNotifications) {
String key = generatePackageKey(sbn.getUserId(), sbn.getPackageName());
- final ArrayMap<String, Integer> children =
+ final ArrayMap<String, NotificationAttributes> children =
mUngroupedNotifications.getOrDefault(key, new ArrayMap<>());
if (children.size() == 0) {
return;
@@ -173,7 +213,7 @@
if (children.containsKey(sbn.getKey())) {
// if this notification was contributing flags that aren't covered by other
// children to the summary, reevaluate flags for the summary
- int flags = children.remove(sbn.getKey());
+ int flags = children.remove(sbn.getKey()).flags;
// this
if (hasAnyFlag(flags, ANY_CHILDREN_FLAGS)) {
updateSummaryFlags = true;
@@ -188,14 +228,29 @@
// If there are no more children left to autogroup, remove the summary
if (children.size() == 0) {
removeSummary = true;
+ } else {
+ childrenAttrs.addAll(children.values());
}
}
}
+
if (removeSummary) {
mCallback.removeAutoGroupSummary(userId, sbn.getPackageName());
} else {
- if (updateSummaryFlags) {
- mCallback.updateAutogroupSummary(userId, sbn.getPackageName(), summaryFlags);
+ NotificationAttributes attr = new NotificationAttributes(summaryFlags,
+ sbn.getNotification().getSmallIcon(), sbn.getNotification().color);
+ boolean iconUpdated = false;
+ if (Flags.autogroupSummaryIconUpdate()) {
+ NotificationAttributes newAttr = updateAutobundledSummaryIcon(sbn.getPackageName(),
+ childrenAttrs, attr);
+ if (!newAttr.equals(attr)) {
+ iconUpdated = true;
+ attr = newAttr;
+ }
+ }
+
+ if (updateSummaryFlags || iconUpdated) {
+ mCallback.updateAutogroupSummary(userId, sbn.getPackageName(), attr);
}
}
if (removeAutogroupOverlay) {
@@ -207,17 +262,139 @@
int getNotGroupedByAppCount(int userId, String pkg) {
synchronized (mUngroupedNotifications) {
String key = generatePackageKey(userId, pkg);
- final ArrayMap<String, Integer> children =
+ final ArrayMap<String, NotificationAttributes> children =
mUngroupedNotifications.getOrDefault(key, new ArrayMap<>());
return children.size();
}
}
+ NotificationAttributes getAutobundledSummaryIconAndColor(@NonNull String packageName,
+ @NonNull List<NotificationAttributes> childrenAttr) {
+ Icon newIcon = null;
+ boolean childrenHaveSameIcon = true;
+ int newColor = Notification.COLOR_INVALID;
+ boolean childrenHaveSameColor = true;
+
+ // Both the icon drawable and the icon background color are updated according to this rule:
+ // - if all child icons are identical => use the common icon
+ // - if child icons are different: use the monochromatic app icon, if exists.
+ // Otherwise fall back to a generic icon representing a stack.
+ for (NotificationAttributes state: childrenAttr) {
+ // Check for icon
+ if (newIcon == null) {
+ newIcon = state.icon;
+ } else {
+ if (!newIcon.sameAs(state.icon)) {
+ childrenHaveSameIcon = false;
+ }
+ }
+ // Check for color
+ if (newColor == Notification.COLOR_INVALID) {
+ newColor = state.iconColor;
+ } else {
+ if (newColor != state.iconColor) {
+ childrenHaveSameColor = false;
+ }
+ }
+ }
+ if (!childrenHaveSameIcon) {
+ newIcon = getMonochromeAppIcon(packageName);
+ }
+ if (!childrenHaveSameColor) {
+ newColor = COLOR_DEFAULT;
+ }
+
+ return new NotificationAttributes(0, newIcon, newColor);
+ }
+
+ NotificationAttributes updateAutobundledSummaryIcon(@NonNull String packageName,
+ @NonNull List<NotificationAttributes> childrenAttr,
+ @NonNull NotificationAttributes oldAttr) {
+ NotificationAttributes newAttr = getAutobundledSummaryIconAndColor(packageName,
+ childrenAttr);
+ Icon newIcon = newAttr.icon;
+ int newColor = newAttr.iconColor;
+ if (newAttr.icon == null) {
+ newIcon = oldAttr.icon;
+ }
+ if (newAttr.iconColor == Notification.COLOR_INVALID) {
+ newColor = oldAttr.iconColor;
+ }
+
+ return new NotificationAttributes(oldAttr.flags, newIcon, newColor);
+ }
+
+ /**
+ * Get the monochrome app icon for an app from the adaptive launcher icon
+ * or a fallback generic icon for autogroup summaries.
+ *
+ * @param pkg packageName of the app
+ * @return a monochrome app icon or a fallback generic icon
+ */
+ @NonNull
+ Icon getMonochromeAppIcon(@NonNull final String pkg) {
+ Icon monochromeIcon = null;
+ final int fallbackIconResId = R.drawable.ic_notification_summary_auto;
+ try {
+ final Drawable appIcon = mPackageManager.getApplicationIcon(pkg);
+ if (appIcon instanceof AdaptiveIconDrawable) {
+ if (((AdaptiveIconDrawable) appIcon).getMonochrome() != null) {
+ monochromeIcon = Icon.createWithResourceAdaptiveDrawable(pkg,
+ ((AdaptiveIconDrawable) appIcon).getSourceDrawableResId(), true,
+ -2.0f * AdaptiveIconDrawable.getExtraInsetFraction());
+ }
+ }
+ } catch (NameNotFoundException e) {
+ Slog.e(TAG, "Failed to getApplicationIcon() in getMonochromeAppIcon()", e);
+ }
+ if (monochromeIcon != null) {
+ return monochromeIcon;
+ } else {
+ return Icon.createWithResource(mContext, fallbackIconResId);
+ }
+ }
+
+ protected static class NotificationAttributes {
+ public final int flags;
+ public final int iconColor;
+ public final Icon icon;
+
+ public NotificationAttributes(int flags, Icon icon, int iconColor) {
+ this.flags = flags;
+ this.icon = icon;
+ this.iconColor = iconColor;
+ }
+
+ public NotificationAttributes(@NonNull NotificationAttributes attr) {
+ this.flags = attr.flags;
+ this.icon = attr.icon;
+ this.iconColor = attr.iconColor;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof NotificationAttributes that)) {
+ return false;
+ }
+ return flags == that.flags && iconColor == that.iconColor && icon.sameAs(that.icon);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(flags, iconColor, icon);
+ }
+ }
+
protected interface Callback {
void addAutoGroup(String key);
void removeAutoGroup(String key);
- void addAutoGroupSummary(int userId, String pkg, String triggeringKey, int flags);
+
+ void addAutoGroupSummary(int userId, String pkg, String triggeringKey,
+ NotificationAttributes summaryAttr);
void removeAutoGroupSummary(int user, String pkg);
- void updateAutogroupSummary(int userId, String pkg, int flags);
+ void updateAutogroupSummary(int userId, String pkg, NotificationAttributes summaryAttr);
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 638382e..6fa737d 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -227,6 +227,7 @@
import android.content.pm.VersionedPackage;
import android.content.res.Resources;
import android.database.ContentObserver;
+import android.graphics.drawable.Icon;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.AudioManagerInternal;
@@ -341,6 +342,7 @@
import com.android.server.job.JobSchedulerInternal;
import com.android.server.lights.LightsManager;
import com.android.server.lights.LogicalLight;
+import com.android.server.notification.GroupHelper.NotificationAttributes;
import com.android.server.notification.ManagedServices.ManagedServiceInfo;
import com.android.server.notification.ManagedServices.UserProfiles;
import com.android.server.notification.toast.CustomToastRecord;
@@ -996,17 +998,19 @@
}
/**
- * This method will update the flags of the summary.
+ * This method will update the flags and/or the icon of the summary.
* It will set it to FLAG_ONGOING_EVENT if any of its group members
- * has the same flag. It will delete the flag otherwise
+ * has the same flag. It will delete the flag otherwise.
+ * It will update the summary notification icon if the group children's
+ * icons are different.
* @param userId user id of the autogroup summary
* @param pkg package of the autogroup summary
- * @param flags the new flags for this summary
+ * @param summaryAttr the new flags and/or icon & color for this summary
* @param isAppForeground true if the app is currently in the foreground.
*/
@GuardedBy("mNotificationLock")
- protected void updateAutobundledSummaryFlags(int userId, String pkg, int flags,
- boolean isAppForeground) {
+ protected void updateAutobundledSummaryLocked(int userId, String pkg,
+ NotificationAttributes summaryAttr, boolean isAppForeground) {
ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
if (summaries == null) {
return;
@@ -1020,8 +1024,16 @@
return;
}
int oldFlags = summary.getSbn().getNotification().flags;
- if (oldFlags != flags) {
- summary.getSbn().getNotification().flags = flags;
+
+ boolean iconUpdated =
+ !summaryAttr.icon.sameAs(summary.getSbn().getNotification().getSmallIcon())
+ || summaryAttr.iconColor != summary.getSbn().getNotification().color;
+
+ if (oldFlags != summaryAttr.flags || iconUpdated) {
+ summary.getSbn().getNotification().flags =
+ summaryAttr.flags != GroupHelper.FLAG_INVALID ? summaryAttr.flags : oldFlags;
+ summary.getSbn().getNotification().setSmallIcon(summaryAttr.icon);
+ summary.getSbn().getNotification().color = summaryAttr.iconColor;
mHandler.post(new EnqueueNotificationRunnable(userId, summary, isAppForeground,
mPostNotificationTrackerFactory.newTracker(null)));
}
@@ -2873,7 +2885,8 @@
private GroupHelper getGroupHelper() {
mAutoGroupAtCount =
getContext().getResources().getInteger(R.integer.config_autoGroupAtCount);
- return new GroupHelper(mAutoGroupAtCount, new GroupHelper.Callback() {
+ return new GroupHelper(getContext(), getContext().getPackageManager(),
+ mAutoGroupAtCount, new GroupHelper.Callback() {
@Override
public void addAutoGroup(String key) {
synchronized (mNotificationLock) {
@@ -2890,8 +2903,9 @@
@Override
public void addAutoGroupSummary(int userId, String pkg, String triggeringKey,
- int flags) {
- NotificationRecord r = createAutoGroupSummary(userId, pkg, triggeringKey, flags);
+ NotificationAttributes summaryAttr) {
+ NotificationRecord r = createAutoGroupSummary(userId, pkg, triggeringKey,
+ summaryAttr.flags, summaryAttr.icon, summaryAttr.iconColor);
if (r != null) {
final boolean isAppForeground =
mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND;
@@ -2908,11 +2922,12 @@
}
@Override
- public void updateAutogroupSummary(int userId, String pkg, int flags) {
+ public void updateAutogroupSummary(int userId, String pkg,
+ NotificationAttributes summaryAttr) {
boolean isAppForeground = pkg != null
&& mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND;
synchronized (mNotificationLock) {
- updateAutobundledSummaryFlags(userId, pkg, flags, isAppForeground);
+ updateAutobundledSummaryLocked(userId, pkg, summaryAttr, isAppForeground);
}
}
});
@@ -6529,7 +6544,7 @@
// Creates a 'fake' summary for a package that has exceeded the solo-notification limit.
NotificationRecord createAutoGroupSummary(int userId, String pkg, String triggeringKey,
- int flagsToSet) {
+ int flagsToSet, Icon summaryIcon, int summaryIconColor) {
NotificationRecord summaryRecord = null;
boolean isPermissionFixed = mPermissionHelper.isPermissionFixed(pkg, userId);
synchronized (mNotificationLock) {
@@ -6555,14 +6570,15 @@
final Bundle extras = new Bundle();
extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
final String channelId = notificationRecord.getChannel().getId();
+
final Notification summaryNotification =
- new Notification.Builder(getContext(), channelId)
- .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
+ new Notification.Builder(getContext(), channelId)
+ .setSmallIcon(summaryIcon)
.setGroupSummary(true)
.setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN)
.setGroup(GroupHelper.AUTOGROUP_KEY)
.setFlag(flagsToSet, true)
- .setColor(adjustedSbn.getNotification().color)
+ .setColor(summaryIconColor)
.build();
summaryNotification.extras.putAll(extras);
Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
index 516fb4a..5eb76e3 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
@@ -15,37 +15,56 @@
*/
package com.android.server.notification;
+import static android.app.Notification.COLOR_DEFAULT;
import static android.app.Notification.FLAG_AUTO_CANCEL;
import static android.app.Notification.FLAG_BUBBLE;
import static android.app.Notification.FLAG_CAN_COLORIZE;
import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
import static android.app.Notification.FLAG_NO_CLEAR;
import static android.app.Notification.FLAG_ONGOING_EVENT;
+import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
import static com.android.server.notification.GroupHelper.BASE_FLAGS;
+import static com.google.common.truth.Truth.assertThat;
+
import static junit.framework.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
import android.annotation.SuppressLint;
import android.app.Notification;
+import android.content.pm.PackageManager;
+import android.graphics.Color;
+import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
import android.os.UserHandle;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.service.notification.StatusBarNotification;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.ArrayMap;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.R;
import com.android.server.UiServiceTestCase;
+import com.android.server.notification.GroupHelper.NotificationAttributes;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -59,23 +78,37 @@
@SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the class.
@RunWith(AndroidJUnit4.class)
public class GroupHelperTest extends UiServiceTestCase {
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
+
private @Mock GroupHelper.Callback mCallback;
+ private @Mock PackageManager mPackageManager;
private final static int AUTOGROUP_AT_COUNT = 7;
private GroupHelper mGroupHelper;
+ private @Mock Icon mSmallIcon;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mGroupHelper = new GroupHelper(AUTOGROUP_AT_COUNT, mCallback);
+ mGroupHelper = new GroupHelper(getContext(), mPackageManager, AUTOGROUP_AT_COUNT,
+ mCallback);
+
+ NotificationRecord r = mock(NotificationRecord.class);
+ StatusBarNotification sbn = getSbn("package", 0, "0", UserHandle.SYSTEM);
+ when(r.getNotification()).thenReturn(sbn.getNotification());
+ when(r.getSbn()).thenReturn(sbn);
+ when(mSmallIcon.sameAs(mSmallIcon)).thenReturn(true);
}
private StatusBarNotification getSbn(String pkg, int id, String tag,
- UserHandle user, String groupKey) {
+ UserHandle user, String groupKey, Icon smallIcon, int iconColor) {
Notification.Builder nb = new Notification.Builder(getContext(), "test_channel_id")
.setContentTitle("A")
- .setWhen(1205);
+ .setWhen(1205)
+ .setSmallIcon(smallIcon)
+ .setColor(iconColor);
if (groupKey != null) {
nb.setGroup(groupKey);
}
@@ -84,23 +117,32 @@
}
private StatusBarNotification getSbn(String pkg, int id, String tag,
+ UserHandle user, String groupKey) {
+ return getSbn(pkg, id, tag, user, groupKey, mSmallIcon, Notification.COLOR_DEFAULT);
+ }
+
+ private StatusBarNotification getSbn(String pkg, int id, String tag,
UserHandle user) {
return getSbn(pkg, id, tag, user, null);
}
+ private NotificationAttributes getNotificationAttributes(int flags) {
+ return new NotificationAttributes(flags, mSmallIcon, COLOR_DEFAULT);
+ }
+
@Test
public void testGetAutogroupSummaryFlags_noChildren() {
- ArrayMap<String, Integer> children = new ArrayMap<>();
+ ArrayMap<String, NotificationAttributes> children = new ArrayMap<>();
assertEquals(BASE_FLAGS, mGroupHelper.getAutogroupSummaryFlags(children));
}
@Test
public void testGetAutogroupSummaryFlags_oneOngoing() {
- ArrayMap<String, Integer> children = new ArrayMap<>();
- children.put("a", 0);
- children.put("b", FLAG_ONGOING_EVENT);
- children.put("c", FLAG_BUBBLE);
+ ArrayMap<String, NotificationAttributes> children = new ArrayMap<>();
+ children.put("a", getNotificationAttributes(0));
+ children.put("b", getNotificationAttributes(FLAG_ONGOING_EVENT));
+ children.put("c", getNotificationAttributes(FLAG_BUBBLE));
assertEquals(FLAG_ONGOING_EVENT | BASE_FLAGS,
mGroupHelper.getAutogroupSummaryFlags(children));
@@ -108,10 +150,10 @@
@Test
public void testGetAutogroupSummaryFlags_oneOngoingNoClear() {
- ArrayMap<String, Integer> children = new ArrayMap<>();
- children.put("a", 0);
- children.put("b", FLAG_ONGOING_EVENT|FLAG_NO_CLEAR);
- children.put("c", FLAG_BUBBLE);
+ ArrayMap<String, NotificationAttributes> children = new ArrayMap<>();
+ children.put("a", getNotificationAttributes(0));
+ children.put("b", getNotificationAttributes(FLAG_ONGOING_EVENT | FLAG_NO_CLEAR));
+ children.put("c", getNotificationAttributes(FLAG_BUBBLE));
assertEquals(FLAG_NO_CLEAR | FLAG_ONGOING_EVENT | BASE_FLAGS,
mGroupHelper.getAutogroupSummaryFlags(children));
@@ -119,10 +161,10 @@
@Test
public void testGetAutogroupSummaryFlags_oneOngoingBubble() {
- ArrayMap<String, Integer> children = new ArrayMap<>();
- children.put("a", 0);
- children.put("b", FLAG_ONGOING_EVENT | FLAG_BUBBLE);
- children.put("c", FLAG_BUBBLE);
+ ArrayMap<String, NotificationAttributes> children = new ArrayMap<>();
+ children.put("a", getNotificationAttributes(0));
+ children.put("b", getNotificationAttributes(FLAG_ONGOING_EVENT | FLAG_BUBBLE));
+ children.put("c", getNotificationAttributes(FLAG_BUBBLE));
assertEquals(FLAG_ONGOING_EVENT | BASE_FLAGS,
mGroupHelper.getAutogroupSummaryFlags(children));
@@ -130,11 +172,11 @@
@Test
public void testGetAutogroupSummaryFlags_multipleOngoing() {
- ArrayMap<String, Integer> children = new ArrayMap<>();
- children.put("a", 0);
- children.put("b", FLAG_ONGOING_EVENT);
- children.put("c", FLAG_BUBBLE);
- children.put("d", FLAG_ONGOING_EVENT);
+ ArrayMap<String, NotificationAttributes> children = new ArrayMap<>();
+ children.put("a", getNotificationAttributes(0));
+ children.put("b", getNotificationAttributes(FLAG_ONGOING_EVENT));
+ children.put("c", getNotificationAttributes(FLAG_BUBBLE));
+ children.put("d", getNotificationAttributes(FLAG_ONGOING_EVENT));
assertEquals(FLAG_ONGOING_EVENT | BASE_FLAGS,
mGroupHelper.getAutogroupSummaryFlags(children));
@@ -142,10 +184,10 @@
@Test
public void testGetAutogroupSummaryFlags_oneAutoCancel() {
- ArrayMap<String, Integer> children = new ArrayMap<>();
- children.put("a", 0);
- children.put("b", FLAG_AUTO_CANCEL);
- children.put("c", FLAG_BUBBLE);
+ ArrayMap<String, NotificationAttributes> children = new ArrayMap<>();
+ children.put("a", getNotificationAttributes(0));
+ children.put("b", getNotificationAttributes(FLAG_AUTO_CANCEL));
+ children.put("c", getNotificationAttributes(FLAG_BUBBLE));
assertEquals(BASE_FLAGS,
mGroupHelper.getAutogroupSummaryFlags(children));
@@ -153,11 +195,11 @@
@Test
public void testGetAutogroupSummaryFlags_allAutoCancel() {
- ArrayMap<String, Integer> children = new ArrayMap<>();
- children.put("a", FLAG_AUTO_CANCEL);
- children.put("b", FLAG_AUTO_CANCEL | FLAG_CAN_COLORIZE);
- children.put("c", FLAG_AUTO_CANCEL);
- children.put("d", FLAG_AUTO_CANCEL | FLAG_FOREGROUND_SERVICE);
+ ArrayMap<String, NotificationAttributes> children = new ArrayMap<>();
+ children.put("a", getNotificationAttributes(FLAG_AUTO_CANCEL));
+ children.put("b", getNotificationAttributes(FLAG_AUTO_CANCEL | FLAG_CAN_COLORIZE));
+ children.put("c", getNotificationAttributes(FLAG_AUTO_CANCEL));
+ children.put("d", getNotificationAttributes(FLAG_AUTO_CANCEL | FLAG_FOREGROUND_SERVICE));
assertEquals(FLAG_AUTO_CANCEL | BASE_FLAGS,
mGroupHelper.getAutogroupSummaryFlags(children));
@@ -165,11 +207,12 @@
@Test
public void testGetAutogroupSummaryFlags_allAutoCancelOneOngoing() {
- ArrayMap<String, Integer> children = new ArrayMap<>();
- children.put("a", FLAG_AUTO_CANCEL);
- children.put("b", FLAG_AUTO_CANCEL | FLAG_CAN_COLORIZE);
- children.put("c", FLAG_AUTO_CANCEL);
- children.put("d", FLAG_AUTO_CANCEL | FLAG_FOREGROUND_SERVICE | FLAG_ONGOING_EVENT);
+ ArrayMap<String, NotificationAttributes> children = new ArrayMap<>();
+ children.put("a", getNotificationAttributes(FLAG_AUTO_CANCEL));
+ children.put("b", getNotificationAttributes(FLAG_AUTO_CANCEL | FLAG_CAN_COLORIZE));
+ children.put("c", getNotificationAttributes(FLAG_AUTO_CANCEL));
+ children.put("d", getNotificationAttributes(
+ FLAG_AUTO_CANCEL | FLAG_FOREGROUND_SERVICE | FLAG_ONGOING_EVENT));
assertEquals(FLAG_AUTO_CANCEL| FLAG_ONGOING_EVENT | BASE_FLAGS,
mGroupHelper.getAutogroupSummaryFlags(children));
@@ -230,11 +273,11 @@
getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM), false);
}
verify(mCallback, times(1)).addAutoGroupSummary(
- anyInt(), eq(pkg), anyString(), eq(BASE_FLAGS));
+ anyInt(), eq(pkg), anyString(), eq(getNotificationAttributes(BASE_FLAGS)));
verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString());
verify(mCallback, never()).removeAutoGroup(anyString());
verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
- verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyInt());
+ verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), any());
}
@Test
@@ -248,11 +291,11 @@
mGroupHelper.onNotificationPosted(sbn, false);
}
verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(),
- eq(BASE_FLAGS | FLAG_ONGOING_EVENT));
+ eq(getNotificationAttributes(BASE_FLAGS | FLAG_ONGOING_EVENT)));
verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString());
verify(mCallback, never()).removeAutoGroup(anyString());
verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
- verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyInt());
+ verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), any());
}
@Test
@@ -266,11 +309,11 @@
mGroupHelper.onNotificationPosted(sbn, false);
}
verify(mCallback, times(1)).addAutoGroupSummary(
- anyInt(), eq(pkg), anyString(), eq(BASE_FLAGS));
+ anyInt(), eq(pkg), anyString(), eq(getNotificationAttributes(BASE_FLAGS)));
verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString());
verify(mCallback, never()).removeAutoGroup(anyString());
verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
- verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyInt());
+ verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), any());
}
@Test
@@ -282,11 +325,11 @@
mGroupHelper.onNotificationPosted(sbn, false);
}
verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(),
- eq(BASE_FLAGS | FLAG_AUTO_CANCEL));
+ eq(getNotificationAttributes(BASE_FLAGS | FLAG_AUTO_CANCEL)));
verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString());
verify(mCallback, never()).removeAutoGroup(anyString());
verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
- verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyInt());
+ verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), any());
}
@Test
@@ -301,11 +344,11 @@
mGroupHelper.onNotificationPosted(sbn, false);
}
verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(),
- eq(BASE_FLAGS | FLAG_AUTO_CANCEL | FLAG_NO_CLEAR));
+ eq(getNotificationAttributes(BASE_FLAGS | FLAG_AUTO_CANCEL | FLAG_NO_CLEAR)));
verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString());
verify(mCallback, never()).removeAutoGroup(anyString());
verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
- verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyInt());
+ verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), any());
}
@Test
@@ -329,8 +372,8 @@
mGroupHelper.onNotificationPosted(notifications.get(0), true);
// Summary should keep FLAG_ONGOING_EVENT if any child has it
- verify(mCallback).updateAutogroupSummary(
- anyInt(), anyString(), eq(BASE_FLAGS | FLAG_ONGOING_EVENT));
+ verify(mCallback).updateAutogroupSummary(anyInt(), anyString(),
+ eq(getNotificationAttributes(BASE_FLAGS | FLAG_ONGOING_EVENT)));
}
@Test
@@ -355,7 +398,8 @@
mGroupHelper.onNotificationRemoved(notifications.get(0));
// Summary is no longer ongoing
- verify(mCallback).updateAutogroupSummary(anyInt(), anyString(), eq(BASE_FLAGS));
+ verify(mCallback).updateAutogroupSummary(anyInt(), anyString(),
+ eq(getNotificationAttributes(BASE_FLAGS)));
}
@Test
@@ -378,8 +422,8 @@
mGroupHelper.onNotificationPosted(notifications.get(0), true);
// Summary is now ongoing
- verify(mCallback).updateAutogroupSummary(
- anyInt(), anyString(), eq(BASE_FLAGS | FLAG_ONGOING_EVENT));
+ verify(mCallback).updateAutogroupSummary(anyInt(), anyString(),
+ eq(getNotificationAttributes(BASE_FLAGS | FLAG_ONGOING_EVENT)));
}
@Test
@@ -403,8 +447,8 @@
mGroupHelper.onNotificationPosted(sbn, true);
// Summary is now ongoing
- verify(mCallback).updateAutogroupSummary(
- anyInt(), anyString(), eq(BASE_FLAGS | FLAG_ONGOING_EVENT));
+ verify(mCallback).updateAutogroupSummary(anyInt(), anyString(),
+ eq(getNotificationAttributes(BASE_FLAGS | FLAG_ONGOING_EVENT)));
}
@Test
@@ -430,7 +474,8 @@
mGroupHelper.onNotificationPosted(sbn, true);
// Summary is no longer ongoing
- verify(mCallback).updateAutogroupSummary(anyInt(), anyString(), eq(BASE_FLAGS));
+ verify(mCallback).updateAutogroupSummary(anyInt(), anyString(),
+ eq(getNotificationAttributes(BASE_FLAGS)));
}
@Test
@@ -455,7 +500,7 @@
mGroupHelper.onNotificationRemoved(notifications.get(1));
// Summary is still ongoing
- verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyInt());
+ verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), any());
}
@Test
@@ -479,7 +524,8 @@
mGroupHelper.onNotificationPosted(notifications.get(0), true);
// Summary should no longer be autocancelable
- verify(mCallback).updateAutogroupSummary(anyInt(), anyString(), eq(BASE_FLAGS));
+ verify(mCallback).updateAutogroupSummary(anyInt(), anyString(),
+ eq(getNotificationAttributes(BASE_FLAGS)));
}
@Test
@@ -505,8 +551,8 @@
mGroupHelper.onNotificationPosted(notifications.get(0), true);
// Summary should now autocancelable
- verify(mCallback).updateAutogroupSummary(
- anyInt(), anyString(), eq(BASE_FLAGS | FLAG_AUTO_CANCEL));
+ verify(mCallback).updateAutogroupSummary(anyInt(), anyString(),
+ eq(getNotificationAttributes(BASE_FLAGS | FLAG_AUTO_CANCEL)));
}
@Test
@@ -530,7 +576,7 @@
mGroupHelper.onNotificationPosted(sbn, true);
// Summary should be still be autocancelable
- verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyInt());
+ verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), any());
}
@Test
@@ -552,7 +598,7 @@
mGroupHelper.onNotificationRemoved(notifications.get(0));
// Summary should still be autocancelable
- verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyInt());
+ verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), any());
}
@Test
@@ -565,7 +611,7 @@
mGroupHelper.onNotificationPosted(sbn, false);
}
verify(mCallback, times(1)).addAutoGroupSummary(
- anyInt(), eq(pkg), anyString(), eq(BASE_FLAGS));
+ anyInt(), eq(pkg), anyString(), eq(getNotificationAttributes(BASE_FLAGS)));
verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString());
verify(mCallback, never()).removeAutoGroup(anyString());
verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
@@ -593,7 +639,7 @@
mGroupHelper.onNotificationPosted(sbn, false);
}
verify(mCallback, times(1)).addAutoGroupSummary(
- anyInt(), eq(pkg), anyString(), eq(BASE_FLAGS));
+ anyInt(), eq(pkg), anyString(), eq(getNotificationAttributes(BASE_FLAGS)));
verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString());
verify(mCallback, never()).removeAutoGroup(anyString());
verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
@@ -622,7 +668,7 @@
mGroupHelper.onNotificationPosted(sbn, false);
}
verify(mCallback, times(1)).addAutoGroupSummary(
- anyInt(), eq(pkg), anyString(), eq(BASE_FLAGS));
+ anyInt(), eq(pkg), anyString(), eq(getNotificationAttributes(BASE_FLAGS)));
verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString());
verify(mCallback, never()).removeAutoGroup(anyString());
verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
@@ -646,8 +692,213 @@
verify(mCallback, times(1)).addAutoGroup(sbn.getKey());
verify(mCallback, never()).removeAutoGroup(anyString());
verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
- verify(mCallback).updateAutogroupSummary(anyInt(), anyString(), eq(BASE_FLAGS));
- verify(mCallback, never()).addAutoGroupSummary(
- anyInt(), anyString(), anyString(), anyInt());
+ verify(mCallback).updateAutogroupSummary(anyInt(), anyString(),
+ eq(getNotificationAttributes(BASE_FLAGS)));
+ verify(mCallback, never()).addAutoGroupSummary(anyInt(), anyString(), anyString(), any());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_AUTOGROUP_SUMMARY_ICON_UPDATE)
+ public void testAddSummary_sameIcon_sameColor() {
+ final String pkg = "package";
+ final Icon icon = mock(Icon.class);
+ when(icon.sameAs(icon)).thenReturn(true);
+ final int iconColor = Color.BLUE;
+ final NotificationAttributes attr = new NotificationAttributes(BASE_FLAGS, icon, iconColor);
+
+ // Add notifications with same icon and color
+ for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
+ StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM, null,
+ icon, iconColor);
+ mGroupHelper.onNotificationPosted(sbn, false);
+ }
+ // Check that the summary would have the same icon and color
+ verify(mCallback, times(1)).addAutoGroupSummary(
+ anyInt(), eq(pkg), anyString(), eq(attr));
+ verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString());
+ verify(mCallback, never()).removeAutoGroup(anyString());
+ verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
+
+ // After auto-grouping, add new notification with the same color
+ StatusBarNotification sbn = getSbn(pkg, AUTOGROUP_AT_COUNT,
+ String.valueOf(AUTOGROUP_AT_COUNT), UserHandle.SYSTEM, null, icon, iconColor);
+ mGroupHelper.onNotificationPosted(sbn, true);
+
+ // Check that the summary was updated
+ //NotificationAttributes newAttr = new NotificationAttributes(BASE_FLAGS, icon, iconColor);
+ verify(mCallback, times(1)).updateAutogroupSummary(anyInt(), anyString(), eq(attr));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_AUTOGROUP_SUMMARY_ICON_UPDATE)
+ public void testAddSummary_diffIcon_diffColor() {
+ final String pkg = "package";
+ final Icon initialIcon = mock(Icon.class);
+ when(initialIcon.sameAs(initialIcon)).thenReturn(true);
+ final int initialIconColor = Color.BLUE;
+
+ // Spy GroupHelper for getMonochromeAppIcon
+ final Icon monochromeIcon = mock(Icon.class);
+ when(monochromeIcon.sameAs(monochromeIcon)).thenReturn(true);
+ GroupHelper groupHelper = spy(mGroupHelper);
+ doReturn(monochromeIcon).when(groupHelper).getMonochromeAppIcon(eq(pkg));
+
+ final NotificationAttributes initialAttr = new NotificationAttributes(BASE_FLAGS,
+ initialIcon, initialIconColor);
+
+ // Add notifications with same icon and color
+ for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
+ StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM, null,
+ initialIcon, initialIconColor);
+ groupHelper.onNotificationPosted(sbn, false);
+ }
+ // Check that the summary would have the same icon and color
+ verify(mCallback, times(1)).addAutoGroupSummary(
+ anyInt(), eq(pkg), anyString(), eq(initialAttr));
+ verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString());
+ verify(mCallback, never()).removeAutoGroup(anyString());
+ verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
+
+ // After auto-grouping, add new notification with a different color
+ final Icon newIcon = mock(Icon.class);
+ final int newIconColor = Color.YELLOW;
+ StatusBarNotification sbn = getSbn(pkg, AUTOGROUP_AT_COUNT,
+ String.valueOf(AUTOGROUP_AT_COUNT), UserHandle.SYSTEM, null, newIcon,
+ newIconColor);
+ groupHelper.onNotificationPosted(sbn, true);
+
+ // Summary should be updated to the default color and the icon to the monochrome icon
+ NotificationAttributes newAttr = new NotificationAttributes(BASE_FLAGS, monochromeIcon,
+ COLOR_DEFAULT);
+ verify(mCallback, times(1)).updateAutogroupSummary(anyInt(), anyString(), eq(newAttr));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_AUTOGROUP_SUMMARY_ICON_UPDATE)
+ public void testAutoGrouped_diffIcon_diffColor_removeChild_updateTo_sameIcon_sameColor() {
+ final String pkg = "package";
+ final Icon initialIcon = mock(Icon.class);
+ when(initialIcon.sameAs(initialIcon)).thenReturn(true);
+ final int initialIconColor = Color.BLUE;
+ final NotificationAttributes initialAttr = new NotificationAttributes(
+ GroupHelper.FLAG_INVALID, initialIcon, initialIconColor);
+
+ // Add AUTOGROUP_AT_COUNT-1 notifications with same icon and color
+ ArrayList<StatusBarNotification> notifications = new ArrayList<>();
+ for (int i = 0; i < AUTOGROUP_AT_COUNT - 1; i++) {
+ StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM, null,
+ initialIcon, initialIconColor);
+ notifications.add(sbn);
+ }
+ // And an additional notification with different icon and color
+ final int lastIdx = AUTOGROUP_AT_COUNT - 1;
+ StatusBarNotification newSbn = getSbn(pkg, lastIdx,
+ String.valueOf(lastIdx), UserHandle.SYSTEM, null, mock(Icon.class),
+ Color.YELLOW);
+ notifications.add(newSbn);
+ for (StatusBarNotification sbn: notifications) {
+ mGroupHelper.onNotificationPosted(sbn, false);
+ }
+
+ // Remove last notification (the only one with different icon and color)
+ mGroupHelper.onNotificationRemoved(notifications.get(lastIdx));
+
+ // Summary should be updated to the common icon and color
+ verify(mCallback, times(1)).updateAutogroupSummary(anyInt(), anyString(), eq(initialAttr));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_AUTOGROUP_SUMMARY_ICON_UPDATE)
+ public void testAutobundledSummaryIcon_sameIcon() {
+ final String pkg = "package";
+ final Icon icon = mock(Icon.class);
+ when(icon.sameAs(icon)).thenReturn(true);
+
+ // Create notifications with the same icon
+ List<NotificationAttributes> childrenAttr = new ArrayList<>();
+ for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
+ childrenAttr.add(new NotificationAttributes(0, icon, COLOR_DEFAULT));
+ }
+
+ //Check that the generated summary icon is the same as the child notifications'
+ Icon summaryIcon = mGroupHelper.getAutobundledSummaryIconAndColor(pkg, childrenAttr).icon;
+ assertThat(summaryIcon).isEqualTo(icon);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_AUTOGROUP_SUMMARY_ICON_UPDATE)
+ public void testAutobundledSummaryIcon_diffIcon() {
+ final String pkg = "package";
+ // Spy GroupHelper for getMonochromeAppIcon
+ final Icon monochromeIcon = mock(Icon.class);
+ GroupHelper groupHelper = spy(mGroupHelper);
+ doReturn(monochromeIcon).when(groupHelper).getMonochromeAppIcon(eq(pkg));
+
+ // Create notifications with different icons
+ List<NotificationAttributes> childrenAttr = new ArrayList<>();
+ for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
+ childrenAttr.add(new NotificationAttributes(0, mock(Icon.class), COLOR_DEFAULT));
+ }
+
+ // Check that the generated summary icon is the monochrome icon
+ Icon summaryIcon = groupHelper.getAutobundledSummaryIconAndColor(pkg, childrenAttr).icon;
+ assertThat(summaryIcon).isEqualTo(monochromeIcon);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_AUTOGROUP_SUMMARY_ICON_UPDATE)
+ public void testAutobundledSummaryIconColor_sameColor() {
+ final String pkg = "package";
+ final int iconColor = Color.BLUE;
+ // Create notifications with the same icon color
+ List<NotificationAttributes> childrenAttr = new ArrayList<>();
+ for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
+ childrenAttr.add(new NotificationAttributes(0, mock(Icon.class), iconColor));
+ }
+
+ // Check that the generated summary icon color is the same as the child notifications'
+ int summaryIconColor = mGroupHelper.getAutobundledSummaryIconAndColor(pkg,
+ childrenAttr).iconColor;
+ assertThat(summaryIconColor).isEqualTo(iconColor);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_AUTOGROUP_SUMMARY_ICON_UPDATE)
+ public void testAutobundledSummaryIconColor_diffColor() {
+ final String pkg = "package";
+ // Create notifications with different icon colors
+ List<NotificationAttributes> childrenAttr = new ArrayList<>();
+ for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
+ childrenAttr.add(new NotificationAttributes(0, mock(Icon.class), i));
+ }
+
+ // Check that the generated summary icon color is the default color
+ int summaryIconColor = mGroupHelper.getAutobundledSummaryIconAndColor(pkg,
+ childrenAttr).iconColor;
+ assertThat(summaryIconColor).isEqualTo(Notification.COLOR_DEFAULT);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_AUTOGROUP_SUMMARY_ICON_UPDATE)
+ public void testMonochromeAppIcon_adaptiveIconExists() throws Exception {
+ final String pkg = "testPackage";
+ final int monochromeIconResId = 1234;
+ AdaptiveIconDrawable adaptiveIcon = mock(AdaptiveIconDrawable.class);
+ Drawable monochromeIcon = mock(Drawable.class);
+ when(mPackageManager.getApplicationIcon(pkg)).thenReturn(adaptiveIcon);
+ when(adaptiveIcon.getMonochrome()).thenReturn(monochromeIcon);
+ when(adaptiveIcon.getSourceDrawableResId()).thenReturn(monochromeIconResId);
+ assertThat(mGroupHelper.getMonochromeAppIcon(pkg).getResId())
+ .isEqualTo(monochromeIconResId);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_AUTOGROUP_SUMMARY_ICON_UPDATE)
+ public void testMonochromeAppIcon_adaptiveIconMissing_fallback() throws Exception {
+ final String pkg = "testPackage";
+ final int fallbackIconResId = R.drawable.ic_notification_summary_auto;
+ when(mPackageManager.getApplicationIcon(pkg)).thenReturn(mock(Drawable.class));
+ assertThat(mGroupHelper.getMonochromeAppIcon(pkg).getResId())
+ .isEqualTo(fallbackIconResId);
}
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 8261dee..3426cbe 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -279,6 +279,7 @@
import com.android.server.job.JobSchedulerInternal;
import com.android.server.lights.LightsManager;
import com.android.server.lights.LogicalLight;
+import com.android.server.notification.GroupHelper.NotificationAttributes;
import com.android.server.notification.NotificationManagerService.NotificationAssistants;
import com.android.server.notification.NotificationManagerService.NotificationListeners;
import com.android.server.notification.NotificationManagerService.PostNotificationTracker;
@@ -658,7 +659,8 @@
// NOTE: Prefer using the @EnableFlag annotation where possible. Do not add any android.app
// flags here.
mSetFlagsRule.disableFlags(Flags.FLAG_REFACTOR_ATTENTION_HELPER,
- Flags.FLAG_POLITE_NOTIFICATIONS);
+ Flags.FLAG_POLITE_NOTIFICATIONS, Flags.FLAG_AUTOGROUP_SUMMARY_ICON_UPDATE);
+
initNMS();
}
@@ -2332,8 +2334,9 @@
mService.mAutobundledSummaries.put(0, new ArrayMap<>());
mService.mAutobundledSummaries.get(0).put("pkg", summary.getKey());
- mService.updateAutobundledSummaryFlags(
- 0, "pkg", GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT, false);
+ mService.updateAutobundledSummaryLocked(0, "pkg",
+ new NotificationAttributes(GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT,
+ mock(Icon.class), 0), false);
waitForIdle();
assertTrue(summary.getSbn().isOngoing());
@@ -2350,7 +2353,9 @@
mService.mAutobundledSummaries.get(0).put("pkg", summary.getKey());
mService.mSummaryByGroupKey.put("pkg", summary);
- mService.updateAutobundledSummaryFlags(0, "pkg", GroupHelper.BASE_FLAGS, false);
+ mService.updateAutobundledSummaryLocked(0, "pkg",
+ new NotificationAttributes(GroupHelper.BASE_FLAGS,
+ mock(Icon.class), 0), false);
waitForIdle();
assertFalse(summary.getSbn().isOngoing());
@@ -3427,8 +3432,8 @@
when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
when(mPermissionHelper.isPermissionFixed(PKG, temp.getUserId())).thenReturn(true);
- NotificationRecord r = mService.createAutoGroupSummary(
- temp.getUserId(), temp.getSbn().getPackageName(), temp.getKey(), 0);
+ NotificationRecord r = mService.createAutoGroupSummary(temp.getUserId(),
+ temp.getSbn().getPackageName(), temp.getKey(), 0, mock(Icon.class), 0);
assertThat(r.isImportanceFixed()).isTrue();
}
@@ -11962,7 +11967,7 @@
// add summary
mService.addNotification(mService.createAutoGroupSummary(nr1.getUserId(),
nr1.getSbn().getPackageName(), nr1.getKey(),
- GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT));
+ GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT, mock(Icon.class), 0));
// cancel both children
mBinderService.cancelNotificationWithTag(PKG, PKG, nr0.getSbn().getTag(),
@@ -11989,8 +11994,9 @@
// add notifications + summary for USER_SYSTEM
mService.addNotification(nr0);
mService.addNotification(nr1);
- mService.addNotification(mService.createAutoGroupSummary(nr1.getUserId(),
- nr1.getSbn().getPackageName(), nr1.getKey(), GroupHelper.BASE_FLAGS));
+ mService.addNotification(
+ mService.createAutoGroupSummary(nr1.getUserId(), nr1.getSbn().getPackageName(),
+ nr1.getKey(), GroupHelper.BASE_FLAGS, mock(Icon.class), 0));
// add notifications + summary for USER_ALL
NotificationRecord nr0_all =
@@ -12000,8 +12006,10 @@
mService.addNotification(nr0_all);
mService.addNotification(nr1_all);
- mService.addNotification(mService.createAutoGroupSummary(nr0_all.getUserId(),
- nr0_all.getSbn().getPackageName(), nr0_all.getKey(), GroupHelper.BASE_FLAGS));
+ mService.addNotification(
+ mService.createAutoGroupSummary(nr0_all.getUserId(),
+ nr0_all.getSbn().getPackageName(),
+ nr0_all.getKey(), GroupHelper.BASE_FLAGS, mock(Icon.class), 0));
// cancel both children for USER_ALL
mBinderService.cancelNotificationWithTag(PKG, PKG, nr0_all.getSbn().getTag(),