Adds an icon to noisy notifications.
Test: manually
Bug: 116622974
Change-Id: I657e81eed9c650f1613caffaea96e6445c2105ef
diff --git a/api/current.txt b/api/current.txt
index dc383fd..a5724fe 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -40366,6 +40366,7 @@
public static class NotificationListenerService.Ranking {
ctor public NotificationListenerService.Ranking();
+ method public boolean audiblyAlerted();
method public boolean canShowBadge();
method public android.app.NotificationChannel getChannel();
method public int getImportance();
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 6d464fb..4f4df5d 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4457,6 +4457,7 @@
contentView.setViewVisibility(R.id.time, View.GONE);
contentView.setImageViewIcon(R.id.profile_badge, null);
contentView.setViewVisibility(R.id.profile_badge, View.GONE);
+ contentView.setViewVisibility(R.id.alerted_icon, View.GONE);
mN.mUsesStandardHeader = false;
}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index b8e0387..56e6aea 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -1461,6 +1461,7 @@
private boolean mShowBadge;
private @UserSentiment int mUserSentiment = USER_SENTIMENT_NEUTRAL;
private boolean mHidden;
+ private boolean mAudiblyAlerted;
private ArrayList<Notification.Action> mSmartActions;
private ArrayList<CharSequence> mSmartReplies;
@@ -1627,6 +1628,15 @@
}
/**
+ * Returns whether this notification alerted the user via sound or vibration.
+ *
+ * @return true if the notification alerted the user, false otherwise.
+ */
+ public boolean audiblyAlerted() {
+ return mAudiblyAlerted;
+ }
+
+ /**
* @hide
*/
@VisibleForTesting
@@ -1635,8 +1645,8 @@
CharSequence explanation, String overrideGroupKey,
NotificationChannel channel, ArrayList<String> overridePeople,
ArrayList<SnoozeCriterion> snoozeCriteria, boolean showBadge,
- int userSentiment, boolean hidden, ArrayList<Notification.Action> smartActions,
- ArrayList<CharSequence> smartReplies) {
+ int userSentiment, boolean hidden, boolean audiblyAlerted,
+ ArrayList<Notification.Action> smartActions, ArrayList<CharSequence> smartReplies) {
mKey = key;
mRank = rank;
mIsAmbient = importance < NotificationManager.IMPORTANCE_LOW;
@@ -1652,6 +1662,7 @@
mShowBadge = showBadge;
mUserSentiment = userSentiment;
mHidden = hidden;
+ mAudiblyAlerted = audiblyAlerted;
mSmartActions = smartActions;
mSmartReplies = smartReplies;
}
@@ -1703,6 +1714,7 @@
private ArrayMap<String, Boolean> mShowBadge;
private ArrayMap<String, Integer> mUserSentiment;
private ArrayMap<String, Boolean> mHidden;
+ private ArrayMap<String, Boolean> mAudiblyAlerted;
private ArrayMap<String, ArrayList<Notification.Action>> mSmartActions;
private ArrayMap<String, ArrayList<CharSequence>> mSmartReplies;
@@ -1733,8 +1745,8 @@
getVisibilityOverride(key), getSuppressedVisualEffects(key),
getImportance(key), getImportanceExplanation(key), getOverrideGroupKey(key),
getChannel(key), getOverridePeople(key), getSnoozeCriteria(key),
- getShowBadge(key), getUserSentiment(key), getHidden(key), getSmartActions(key),
- getSmartReplies(key));
+ getShowBadge(key), getUserSentiment(key), getHidden(key),
+ getAudiblyAlerted(key), getSmartActions(key), getSmartReplies(key));
return rank >= 0;
}
@@ -1872,6 +1884,16 @@
return hidden == null ? false : hidden.booleanValue();
}
+ private boolean getAudiblyAlerted(String key) {
+ synchronized (this) {
+ if (mAudiblyAlerted == null) {
+ buildAudiblyAlertedLocked();
+ }
+ }
+ Boolean audiblyAlerted = mAudiblyAlerted.get(key);
+ return audiblyAlerted == null ? false : audiblyAlerted.booleanValue();
+ }
+
private ArrayList<Notification.Action> getSmartActions(String key) {
synchronized (this) {
if (mSmartActions == null) {
@@ -2007,6 +2029,11 @@
}
// Locked by 'this'
+ private void buildAudiblyAlertedLocked() {
+ mAudiblyAlerted = buildBooleanMapFromBundle(mRankingUpdate.getAudiblyAlerted());
+ }
+
+ // Locked by 'this'
private void buildSmartActions() {
Bundle smartActions = mRankingUpdate.getSmartActions();
mSmartActions = new ArrayMap<>(smartActions.size());
diff --git a/core/java/android/service/notification/NotificationRankingUpdate.java b/core/java/android/service/notification/NotificationRankingUpdate.java
index c67fad0..b561bfd 100644
--- a/core/java/android/service/notification/NotificationRankingUpdate.java
+++ b/core/java/android/service/notification/NotificationRankingUpdate.java
@@ -39,13 +39,14 @@
private final Bundle mHidden;
private final Bundle mSmartActions;
private final Bundle mSmartReplies;
+ private final Bundle mAudiblyAlerted;
public NotificationRankingUpdate(String[] keys, String[] interceptedKeys,
Bundle visibilityOverrides, Bundle suppressedVisualEffects,
int[] importance, Bundle explanation, Bundle overrideGroupKeys,
Bundle channels, Bundle overridePeople, Bundle snoozeCriteria,
Bundle showBadge, Bundle userSentiment, Bundle hidden, Bundle smartActions,
- Bundle smartReplies) {
+ Bundle smartReplies, Bundle audiblyAlerted) {
mKeys = keys;
mInterceptedKeys = interceptedKeys;
mVisibilityOverrides = visibilityOverrides;
@@ -61,6 +62,7 @@
mHidden = hidden;
mSmartActions = smartActions;
mSmartReplies = smartReplies;
+ mAudiblyAlerted = audiblyAlerted;
}
public NotificationRankingUpdate(Parcel in) {
@@ -80,6 +82,7 @@
mHidden = in.readBundle();
mSmartActions = in.readBundle();
mSmartReplies = in.readBundle();
+ mAudiblyAlerted = in.readBundle();
}
@Override
@@ -104,6 +107,7 @@
out.writeBundle(mHidden);
out.writeBundle(mSmartActions);
out.writeBundle(mSmartReplies);
+ out.writeBundle(mAudiblyAlerted);
}
public static final Parcelable.Creator<NotificationRankingUpdate> CREATOR
@@ -176,4 +180,8 @@
public Bundle getSmartReplies() {
return mSmartReplies;
}
+
+ public Bundle getAudiblyAlerted() {
+ return mAudiblyAlerted;
+ }
}
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index 81da76d..fa30221 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -61,6 +61,7 @@
private View mCameraIcon;
private View mMicIcon;
private View mAppOps;
+ private View mAudiblyAlertedIcon;
private int mIconColor;
private int mOriginalNotificationColor;
private boolean mExpanded;
@@ -121,6 +122,7 @@
mMicIcon = findViewById(com.android.internal.R.id.mic);
mOverlayIcon = findViewById(com.android.internal.R.id.overlay);
mAppOps = findViewById(com.android.internal.R.id.app_ops);
+ mAudiblyAlertedIcon = findViewById(com.android.internal.R.id.alerted_icon);
}
@Override
@@ -216,6 +218,11 @@
layoutRight = end - paddingEnd;
end = layoutLeft = layoutRight - child.getMeasuredWidth();
}
+ if (child == mAudiblyAlertedIcon) {
+ int paddingEnd = mContentEndMargin;
+ layoutRight = end - paddingEnd;
+ end = layoutLeft = layoutRight - child.getMeasuredWidth();
+ }
if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
int ltrLeft = layoutLeft;
layoutLeft = getWidth() - layoutRight;
@@ -337,6 +344,11 @@
? View.VISIBLE : View.GONE);
}
+ /** Updates icon visibility based on the noisiness of the notification. */
+ public void setAudiblyAlerted(boolean audiblyAlerted) {
+ mAudiblyAlertedIcon.setVisibility(audiblyAlerted ? View.VISIBLE : View.GONE);
+ }
+
private void updateExpandButton() {
int drawableId;
int contentDescriptionId;
diff --git a/core/res/res/drawable/ic_notifications_alerted.xml b/core/res/res/drawable/ic_notifications_alerted.xml
new file mode 100644
index 0000000..4bfac37
--- /dev/null
+++ b/core/res/res/drawable/ic_notifications_alerted.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2018 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:pathData="M7.58 4.08L6.15 2.65C3.75 4.48 2.17 7.3 2.03 10.5h2c.15-2.65 1.51-4.97 3.55-6.42zm12.39 6.42h2c-.15-3.2-1.73-6.02-4.12-7.85l-1.42 1.43c2.02 1.45 3.39 3.77 3.54 6.42zM18 11c0-3.07-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.63 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2v-5zm-6 11c.14 0 .27-.01.4-.04.65-.14 1.18-.58 1.44-1.18.1-.24.15-.5.15-.78h-4c.01 1.1.9 2 2.01 2z"
+ android:fillColor="#FF000000" />
+</vector>
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index 8b1f28b..4ee9731 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -126,6 +126,19 @@
android:visibility="gone"
android:contentDescription="@string/notification_work_profile_content_description"
/>
+ <ImageView
+ android:id="@+id/alerted_icon"
+ android:layout_width="@dimen/notification_alerted_size"
+ android:layout_height="@dimen/notification_alerted_size"
+ android:layout_gravity="center"
+ android:layout_marginStart="4dp"
+ android:paddingTop="1dp"
+ android:scaleType="fitCenter"
+ android:visibility="gone"
+ android:contentDescription="@string/notification_alerted_content_description"
+ android:src="@drawable/ic_notifications_alerted"
+ android:tint="@color/notification_secondary_text_color_light"
+ />
<LinearLayout
android:id="@+id/app_ops"
android:layout_height="match_parent"
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index ba483fb..b65c0fd 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -426,6 +426,9 @@
<!-- Size of the profile badge for notifications -->
<dimen name="notification_badge_size">12dp</dimen>
+ <!-- Size of the alerted icon for notifications -->
+ <dimen name="notification_alerted_size">18dp</dimen>
+
<!-- Keyguard dimensions -->
<!-- TEMP -->
<dimen name="kg_security_panel_height">600dp</dimen>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 8b7cafb..8d3992d 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4820,6 +4820,9 @@
<!-- Content description of the work profile icon in the notification. -->
<string name="notification_work_profile_content_description">Work profile</string>
+ <!-- Content description of the alerting icon in the notification. [CHAR_LIMIT=NONE] -->
+ <string name="notification_alerted_content_description">Alerted</string>
+
<!-- Content description of the expand button icon in the notification when collaped.-->
<string name="expand_button_content_description_collapsed">Expand</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 670a4a2..5418e03 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -215,6 +215,7 @@
<java-symbol type="id" name="pin_error_message" />
<java-symbol type="id" name="timePickerLayout" />
<java-symbol type="id" name="profile_badge" />
+ <java-symbol type="id" name="alerted_icon" />
<java-symbol type="id" name="transitionPosition" />
<java-symbol type="id" name="selection_start_handle" />
<java-symbol type="id" name="selection_end_handle" />
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 92765bb..7581d8c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -24,7 +24,6 @@
import android.view.ViewGroup;
import com.android.systemui.Dependency;
-import com.android.systemui.InitController;
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -380,6 +379,7 @@
}
row.showAppOpsIcons(entry.mActiveAppOps);
+ row.setAudiblyAlerted(entry.audiblyAlerted);
}
Trace.beginSection("NotificationPresenter#onUpdateRowStates");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
index 3539fff..b84b77c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
@@ -51,13 +51,14 @@
import android.view.View;
import android.widget.ImageView;
+import androidx.annotation.Nullable;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.Dependency;
import com.android.systemui.ForegroundServiceController;
-import com.android.systemui.InitController;
import com.android.systemui.statusbar.InflationTask;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
@@ -75,8 +76,6 @@
import java.util.List;
import java.util.Objects;
-import androidx.annotation.Nullable;
-
/**
* The list of currently displaying notifications.
*/
@@ -102,6 +101,7 @@
public String key;
public StatusBarNotification notification;
public NotificationChannel channel;
+ public boolean audiblyAlerted;
public StatusBarIconView icon;
public StatusBarIconView expandedIcon;
public ExpandableNotificationRow row; // the outer expanded view
@@ -154,6 +154,7 @@
public void populateFromRanking(@NonNull Ranking ranking) {
channel = ranking.getChannel();
+ audiblyAlerted = ranking.audiblyAlerted();
snoozeCriteria = ranking.getSnoozeCriteria();
userSentiment = ranking.getUserSentiment();
smartActions = ranking.getSmartActions() == null
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 965fb13..5166e06 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -16,14 +16,22 @@
package com.android.systemui.statusbar.notification.row;
-import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
-import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_AMBIENT;
-import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_CONTRACTED;
-import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;
-import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_AMBIENT;
-import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_HEADS_UP;
-import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_PUBLIC;
-import static com.android.systemui.statusbar.notification.row.NotificationInflater.InflationCallback;
+import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator
+ .ExpandAnimationParameters;
+import static com.android.systemui.statusbar.notification.row.NotificationContentView
+ .VISIBLE_TYPE_AMBIENT;
+import static com.android.systemui.statusbar.notification.row.NotificationContentView
+ .VISIBLE_TYPE_CONTRACTED;
+import static com.android.systemui.statusbar.notification.row.NotificationContentView
+ .VISIBLE_TYPE_HEADSUP;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater
+ .FLAG_CONTENT_VIEW_AMBIENT;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater
+ .FLAG_CONTENT_VIEW_HEADS_UP;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater
+ .FLAG_CONTENT_VIEW_PUBLIC;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater
+ .InflationCallback;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -1658,6 +1666,17 @@
mPublicLayout.showAppOpsIcons(activeOps);
}
+ /** Sets whether the notification being displayed audibly alerted the user. */
+ public void setAudiblyAlerted(boolean audiblyAlerted) {
+ if (NotificationUtils.useNewInterruptionModel(mContext)) {
+ if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() != null) {
+ mChildrenContainer.getHeaderView().setAudiblyAlerted(audiblyAlerted);
+ }
+ mPrivateLayout.setAudiblyAlerted(audiblyAlerted);
+ mPublicLayout.setAudiblyAlerted(audiblyAlerted);
+ }
+ }
+
public View.OnClickListener getAppOpsOnClickListener() {
return mOnAppOpsClickListener;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 11cf8e0..fa3fa5b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -1551,6 +1551,19 @@
}
}
+ /** Sets whether the notification being displayed audibly alerted the user. */
+ public void setAudiblyAlerted(boolean audiblyAlerted) {
+ if (mContractedChild != null && mContractedWrapper.getNotificationHeader() != null) {
+ mContractedWrapper.getNotificationHeader().setAudiblyAlerted(audiblyAlerted);
+ }
+ if (mExpandedChild != null && mExpandedWrapper.getNotificationHeader() != null) {
+ mExpandedWrapper.getNotificationHeader().setAudiblyAlerted(audiblyAlerted);
+ }
+ if (mHeadsUpChild != null && mHeadsUpWrapper.getNotificationHeader() != null) {
+ mHeadsUpWrapper.getNotificationHeader().setAudiblyAlerted(audiblyAlerted);
+ }
+ }
+
public NotificationHeaderView getContractedNotificationHeader() {
if (mContractedChild != null) {
return mContractedWrapper.getNotificationHeader();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java
index 459dc5d..0251f64 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java
@@ -437,21 +437,23 @@
outRanking.getImportance(), outRanking.getImportanceExplanation(),
outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null,
outRanking.canShowBadge(), outRanking.getUserSentiment(), true,
- null, null);
+ false, null, null);
} else if (key.equals(TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY)) {
outRanking.populate(key, outRanking.getRank(),
outRanking.matchesInterruptionFilter(),
outRanking.getVisibilityOverride(), 255,
outRanking.getImportance(), outRanking.getImportanceExplanation(),
outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null,
- outRanking.canShowBadge(), outRanking.getUserSentiment(), true, null, null);
+ outRanking.canShowBadge(), outRanking.getUserSentiment(), true, false, null,
+ null);
} else {
outRanking.populate(key, outRanking.getRank(),
outRanking.matchesInterruptionFilter(),
outRanking.getVisibilityOverride(), outRanking.getSuppressedVisualEffects(),
outRanking.getImportance(), outRanking.getImportanceExplanation(),
outRanking.getOverrideGroupKey(), NOTIFICATION_CHANNEL, null, null,
- outRanking.canShowBadge(), outRanking.getUserSentiment(), false, null,
+ outRanking.canShowBadge(), outRanking.getUserSentiment(), false, false,
+ null,
null);
}
return true;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index fb4ecd1..9c68e7d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -19,7 +19,6 @@
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.assertFalse;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
@@ -168,7 +167,7 @@
0,
NotificationManager.IMPORTANCE_DEFAULT,
null, null,
- null, null, null, true, sentiment, false, null, null);
+ null, null, null, true, sentiment, false, false, null, null);
return true;
}).when(mRankingMap).getRanking(eq(key), any(NotificationListenerService.Ranking.class));
}
@@ -186,7 +185,7 @@
NotificationManager.IMPORTANCE_DEFAULT,
null, null,
null, null, null, true,
- NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL, false,
+ NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL, false, false,
smartActions, null);
return true;
}).when(mRankingMap).getRanking(eq(key), any(NotificationListenerService.Ranking.class));
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 924b075..f87a5f7 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -4756,6 +4756,10 @@
applyZenModeLocked(r);
mRankingHelper.sort(mNotificationList);
+ if (!r.isHidden()) {
+ buzzBeepBlinkLocked(r);
+ }
+
if (notification.getSmallIcon() != null) {
StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
mListeners.notifyPostedLocked(r, old);
@@ -4788,9 +4792,6 @@
+ n.getPackageName());
}
- if (!r.isHidden()) {
- buzzBeepBlinkLocked(r);
- }
maybeRecordInterruptionLocked(r);
} finally {
int N = mEnqueuedNotifications.size();
@@ -5157,6 +5158,7 @@
.setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
}
+ record.setAudiblyAlerted(buzz || beep);
}
@GuardedBy("mNotificationLock")
@@ -6561,6 +6563,7 @@
Bundle hidden = new Bundle();
Bundle smartActions = new Bundle();
Bundle smartReplies = new Bundle();
+ Bundle audiblyAlerted = new Bundle();
for (int i = 0; i < N; i++) {
NotificationRecord record = mNotificationList.get(i);
if (!isVisibleToListener(record.sbn, info)) {
@@ -6590,6 +6593,7 @@
hidden.putBoolean(key, record.isHidden());
smartActions.putParcelableArrayList(key, record.getSmartActions());
smartReplies.putCharSequenceArrayList(key, record.getSmartReplies());
+ audiblyAlerted.putBoolean(key, record.getAudiblyAlerted());
}
final int M = keys.size();
String[] keysAr = keys.toArray(new String[M]);
@@ -6601,7 +6605,7 @@
return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
channels, overridePeople, snoozeCriteria, showBadge, userSentiment, hidden,
- smartActions, smartReplies);
+ smartActions, smartReplies, audiblyAlerted);
}
boolean hasCompanionDevice(ManagedServiceInfo info) {
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index e9f2718..84d0c01 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -170,6 +170,7 @@
private final NotificationStats mStats;
private int mUserSentiment;
private boolean mIsInterruptive;
+ private boolean mAudiblyAlerted;
private boolean mTextChanged;
private boolean mRecordedInterruption;
private int mNumberOfSmartRepliesAdded;
@@ -1023,6 +1024,10 @@
}
}
+ public void setAudiblyAlerted(boolean audiblyAlerted) {
+ mAudiblyAlerted = audiblyAlerted;
+ }
+
public void setTextChanged(boolean textChanged) {
mTextChanged = textChanged;
}
@@ -1039,6 +1044,11 @@
return mIsInterruptive;
}
+ /** Returns true if the notification audibly alerted the user. */
+ public boolean getAudiblyAlerted() {
+ return mAudiblyAlerted;
+ }
+
protected void setPeopleOverride(ArrayList<String> people) {
mPeopleOverride = people;
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 59eab3f..9da204f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -417,6 +417,7 @@
verifyLights();
assertTrue(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -429,6 +430,7 @@
verifyNeverVibrate();
verify(mAccessibilityService, times(1)).sendAccessibilityEvent(any(), anyInt());
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
}
@Test
@@ -439,6 +441,7 @@
verifyBeep();
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
}
@Test
@@ -449,6 +452,7 @@
verifyNeverBeep();
assertFalse(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -461,6 +465,7 @@
verifyNeverBeep();
verifyNeverVibrate();
assertFalse(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -473,6 +478,7 @@
verifyNeverBeep();
verifyNeverVibrate();
assertFalse(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -489,6 +495,7 @@
verifyBeepLooped();
verify(mAccessibilityService, times(2)).sendAccessibilityEvent(any(), anyInt());
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
}
@Test
@@ -517,6 +524,7 @@
verifyNeverStopAudio();
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
}
@Test
@@ -530,7 +538,9 @@
verifyNeverStopAudio();
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
assertFalse(s.isInterruptive());
+ assertFalse(s.getAudiblyAlerted());
}
/**
@@ -567,6 +577,7 @@
mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
verifyNeverStopAudio();
assertTrue(other.isInterruptive());
+ assertTrue(other.getAudiblyAlerted());
}
@Test
@@ -592,12 +603,14 @@
// set up internal state
mService.buzzBeepBlinkLocked(r);
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
Mockito.reset(mRingtonePlayer);
// quiet update should stop making noise
mService.buzzBeepBlinkLocked(s);
verifyStopAudio();
assertFalse(s.isInterruptive());
+ assertFalse(s.getAudiblyAlerted());
}
@Test
@@ -609,12 +622,14 @@
// set up internal state
mService.buzzBeepBlinkLocked(r);
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
Mockito.reset(mRingtonePlayer);
// stop making noise - this is a weird corner case, but quiet should override once
mService.buzzBeepBlinkLocked(s);
verifyStopAudio();
assertFalse(s.isInterruptive());
+ assertFalse(s.getAudiblyAlerted());
}
@Test
@@ -631,6 +646,7 @@
verify(mService, times(1)).playInCallNotification();
verifyNeverBeep(); // doesn't play normal beep
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
}
@Test
@@ -650,6 +666,7 @@
eq(effect), anyString(),
(AudioAttributes) anyObject());
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
}
@Test
@@ -667,6 +684,7 @@
verifyNeverVibrate();
verifyBeepLooped();
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
}
@Test
@@ -686,6 +704,7 @@
verify(mRingtonePlayer, never()).playAsync
(anyObject(), anyObject(), anyBoolean(), anyObject());
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
}
@Test
@@ -702,6 +721,7 @@
verifyDelayedVibrateLooped();
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
}
@Test
@@ -713,6 +733,7 @@
verifyNeverBeep();
verifyVibrate();
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
}
@Test
@@ -722,6 +743,7 @@
mService.buzzBeepBlinkLocked(r);
verifyVibrateLooped();
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
}
@Test
@@ -737,6 +759,7 @@
mService.buzzBeepBlinkLocked(r);
verifyVibrate();
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
}
@Test
@@ -747,6 +770,7 @@
verifyNeverBeep();
assertFalse(child.isInterruptive());
+ assertFalse(child.getAudiblyAlerted());
}
@Test
@@ -759,6 +783,7 @@
verifyBeepLooped();
// summaries are never interruptive for notification counts
assertFalse(summary.isInterruptive());
+ assertTrue(summary.getAudiblyAlerted());
}
@Test
@@ -769,6 +794,7 @@
verifyBeepLooped();
assertTrue(nonGroup.isInterruptive());
+ assertTrue(nonGroup.getAudiblyAlerted());
}
@Test
@@ -780,6 +806,7 @@
verifyNeverBeep();
assertFalse(summary.isInterruptive());
+ assertFalse(summary.getAudiblyAlerted());
}
@Test
@@ -790,6 +817,7 @@
verifyBeepLooped();
assertTrue(child.isInterruptive());
+ assertTrue(child.getAudiblyAlerted());
}
@Test
@@ -800,6 +828,7 @@
verifyBeepLooped();
assertTrue(nonGroup.isInterruptive());
+ assertTrue(nonGroup.getAudiblyAlerted());
}
@Test
@@ -810,6 +839,7 @@
verifyBeepLooped();
assertTrue(group.isInterruptive());
+ assertTrue(group.getAudiblyAlerted());
}
@Test
@@ -822,11 +852,13 @@
mService.buzzBeepBlinkLocked(r);
Mockito.reset(mVibrator);
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
// update should not beep
mService.buzzBeepBlinkLocked(s);
verifyNeverVibrate();
assertFalse(s.isInterruptive());
+ assertFalse(s.getAudiblyAlerted());
}
@Test
@@ -839,6 +871,7 @@
verifyNeverStopVibrate();
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
}
@Test
@@ -852,7 +885,9 @@
verifyNeverStopVibrate();
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
assertFalse(s.isInterruptive());
+ assertFalse(s.getAudiblyAlerted());
}
@Test
@@ -871,8 +906,11 @@
mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
verifyNeverStopVibrate();
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
assertTrue(other.isInterruptive());
+ assertTrue(other.getAudiblyAlerted());
assertFalse(s.isInterruptive());
+ assertFalse(s.getAudiblyAlerted());
}
@Test
@@ -888,6 +926,7 @@
mService.buzzBeepBlinkLocked(other);
verifyNeverStopVibrate();
assertFalse(other.isInterruptive());
+ assertFalse(other.getAudiblyAlerted());
}
@Test
@@ -904,7 +943,9 @@
mService.buzzBeepBlinkLocked(s);
verifyStopVibrate();
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
assertFalse(s.isInterruptive());
+ assertFalse(s.getAudiblyAlerted());
}
@Test
@@ -921,7 +962,9 @@
mService.buzzBeepBlinkLocked(s);
verifyStopVibrate();
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
assertFalse(s.isInterruptive());
+ assertFalse(s.getAudiblyAlerted());
}
@Test
@@ -939,7 +982,9 @@
mService.buzzBeepBlinkLocked(s);
verifyStopVibrate();
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
assertFalse(s.isInterruptive());
+ assertFalse(s.getAudiblyAlerted());
}
@Test
@@ -957,6 +1002,7 @@
mService.buzzBeepBlinkLocked(r);
verifyNeverBeep();
assertFalse(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -968,6 +1014,7 @@
mService.buzzBeepBlinkLocked(r);
verifyNeverBeep();
assertFalse(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -1010,6 +1057,7 @@
mService.buzzBeepBlinkLocked(r);
verifyNeverBeep();
assertFalse(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -1043,6 +1091,7 @@
mService.buzzBeepBlinkLocked(r);
verifyNeverLights();
assertFalse(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -1052,6 +1101,7 @@
mService.buzzBeepBlinkLocked(r);
verifyNeverLights();
assertFalse(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -1060,6 +1110,7 @@
mService.buzzBeepBlinkLocked(r);
verifyLights();
assertTrue(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
r = getLightsOnceNotification();
r.isUpdate = true;
@@ -1067,6 +1118,7 @@
// checks that lights happened once, i.e. this new call didn't trigger them again
verifyLights();
assertFalse(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -1076,6 +1128,7 @@
mService.buzzBeepBlinkLocked(r);
verifyNeverLights();
assertFalse(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -1084,6 +1137,7 @@
mService.buzzBeepBlinkLocked(r);
verifyNeverLights();
assertFalse(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -1093,6 +1147,7 @@
mService.buzzBeepBlinkLocked(r);
verifyNeverLights();
assertFalse(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -1102,6 +1157,7 @@
mService.buzzBeepBlinkLocked(r);
verifyNeverLights();
assertFalse(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -1111,6 +1167,7 @@
mService.buzzBeepBlinkLocked(r);
verifyNeverLights();
assertFalse(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -1121,6 +1178,7 @@
verifyNeverLights();
assertFalse(child.isInterruptive());
+ assertFalse(child.getAudiblyAlerted());
}
@Test
@@ -1133,6 +1191,7 @@
verifyLights();
// summaries should never count for interruptiveness counts
assertFalse(summary.isInterruptive());
+ assertFalse(summary.getAudiblyAlerted());
}
@Test
@@ -1143,6 +1202,7 @@
verifyLights();
assertTrue(nonGroup.isInterruptive());
+ assertFalse(nonGroup.getAudiblyAlerted());
}
@Test
@@ -1154,6 +1214,7 @@
verifyNeverLights();
assertFalse(summary.isInterruptive());
+ assertFalse(summary.getAudiblyAlerted());
}
@Test
@@ -1164,6 +1225,7 @@
verifyLights();
assertTrue(child.isInterruptive());
+ assertFalse(child.getAudiblyAlerted());
}
@Test
@@ -1174,6 +1236,7 @@
verifyLights();
assertTrue(nonGroup.isInterruptive());
+ assertFalse(nonGroup.getAudiblyAlerted());
}
@Test
@@ -1184,6 +1247,7 @@
verifyLights();
assertTrue(group.isInterruptive());
+ assertFalse(group.getAudiblyAlerted());
}
static class VibrateRepeatMatcher implements ArgumentMatcher<VibrationEffect> {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
index f255d49..0d7b584 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
@@ -38,12 +38,10 @@
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
-import android.os.Parcel;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.NotificationRankingUpdate;
import android.service.notification.SnoozeCriterion;
-import android.service.notification.StatusBarNotification;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
@@ -94,6 +92,7 @@
assertEquals(getShowBadge(i), ranking.canShowBadge());
assertEquals(getUserSentiment(i), ranking.getUserSentiment());
assertEquals(getHidden(i), ranking.isSuspended());
+ assertEquals(audiblyAlerted(i), ranking.audiblyAlerted());
assertActionsEqual(getSmartActions(key, i), ranking.getSmartActions());
assertEquals(getSmartReplies(key, i), ranking.getSmartReplies());
}
@@ -114,6 +113,7 @@
Bundle mHidden = new Bundle();
Bundle smartActions = new Bundle();
Bundle smartReplies = new Bundle();
+ Bundle audiblyAlerted = new Bundle();
for (int i = 0; i < mKeys.length; i++) {
String key = mKeys[i];
@@ -133,12 +133,13 @@
mHidden.putBoolean(key, getHidden(i));
smartActions.putParcelableArrayList(key, getSmartActions(key, i));
smartReplies.putCharSequenceArrayList(key, getSmartReplies(key, i));
+ audiblyAlerted.putBoolean(key, audiblyAlerted(i));
}
NotificationRankingUpdate update = new NotificationRankingUpdate(mKeys,
interceptedKeys.toArray(new String[0]), visibilityOverrides,
suppressedVisualEffects, importance, explanation, overrideGroupKeys,
channels, overridePeople, snoozeCriteria, showBadge, userSentiment, mHidden,
- smartActions, smartReplies);
+ smartActions, smartReplies, audiblyAlerted);
return update;
}
@@ -190,6 +191,10 @@
return index % 2 == 0;
}
+ private boolean audiblyAlerted(int index) {
+ return index < 2;
+ }
+
private ArrayList<String> getPeople(String key, int index) {
ArrayList<String> people = new ArrayList<>();
for (int i = 0; i < index; i++) {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
index 1b59e75..9b41fdd 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -801,4 +801,16 @@
assertEquals(1.0f, record.getContactAffinity());
assertEquals(IMPORTANCE_LOW, record.getImportance());
}
+
+ @Test
+ public void testSetAudiblyAlerted() {
+ StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
+ true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+ false /* lights */, false /* defaultLights */, groupId /* group */);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+ record.setAudiblyAlerted(true);
+
+ assertTrue(record.getAudiblyAlerted());
+ }
}