DO NOT MERGE Allow NAS to suggest importances for notifications
(In addition to the existing 'change importance' adjustment). Fixes: 262578968 Test: NotificationListenerServiceTest Test: NotificationRecordExtractorDataTest Test: NotificationRecordTest TesT: CTS in same topic Change-Id: I510414cba256cfb9fb19fa659947e7737f6fd4e1
This commit is contained in:
@@ -52,7 +52,7 @@ public final class Adjustment implements Parcelable {
|
||||
/** @hide */
|
||||
@StringDef (prefix = { "KEY_" }, value = {
|
||||
KEY_CONTEXTUAL_ACTIONS, KEY_GROUP_KEY, KEY_IMPORTANCE, KEY_PEOPLE, KEY_SNOOZE_CRITERIA,
|
||||
KEY_TEXT_REPLIES, KEY_USER_SENTIMENT
|
||||
KEY_TEXT_REPLIES, KEY_USER_SENTIMENT, KEY_IMPORTANCE_PROPOSAL
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface Keys {}
|
||||
@@ -121,6 +121,19 @@ public final class Adjustment implements Parcelable {
|
||||
*/
|
||||
public static final String KEY_IMPORTANCE = "key_importance";
|
||||
|
||||
/**
|
||||
* Weaker than {@link #KEY_IMPORTANCE}, this adjustment suggests an importance rather than
|
||||
* mandates an importance change.
|
||||
*
|
||||
* A notification listener can interpet this suggestion to show the user a prompt to change
|
||||
* notification importance for the notification (or type, or app) moving forward.
|
||||
*
|
||||
* Data type: int, one of importance values e.g.
|
||||
* {@link android.app.NotificationManager#IMPORTANCE_MIN}.
|
||||
* @hide
|
||||
*/
|
||||
public static final String KEY_IMPORTANCE_PROPOSAL = "key_importance_proposal";
|
||||
|
||||
/**
|
||||
* Data type: float, a ranking score from 0 (lowest) to 1 (highest).
|
||||
* Used to rank notifications inside that fall under the same classification (i.e. alerting,
|
||||
|
||||
@@ -1711,6 +1711,8 @@ public abstract class NotificationListenerService extends Service {
|
||||
private ShortcutInfo mShortcutInfo;
|
||||
private @RankingAdjustment int mRankingAdjustment;
|
||||
private boolean mIsBubble;
|
||||
// Notification assistant importance suggestion
|
||||
private int mProposedImportance;
|
||||
|
||||
private static final int PARCEL_VERSION = 2;
|
||||
|
||||
@@ -1748,6 +1750,7 @@ public abstract class NotificationListenerService extends Service {
|
||||
out.writeParcelable(mShortcutInfo, flags);
|
||||
out.writeInt(mRankingAdjustment);
|
||||
out.writeBoolean(mIsBubble);
|
||||
out.writeInt(mProposedImportance);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@@ -1786,6 +1789,7 @@ public abstract class NotificationListenerService extends Service {
|
||||
mShortcutInfo = in.readParcelable(cl, android.content.pm.ShortcutInfo.class);
|
||||
mRankingAdjustment = in.readInt();
|
||||
mIsBubble = in.readBoolean();
|
||||
mProposedImportance = in.readInt();
|
||||
}
|
||||
|
||||
|
||||
@@ -1877,6 +1881,22 @@ public abstract class NotificationListenerService extends Service {
|
||||
return mRankingScore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the proposed importance provided by the {@link NotificationAssistantService}.
|
||||
*
|
||||
* This can be used to suggest that the user change the importance of this type of
|
||||
* notification moving forward. A value of
|
||||
* {@link NotificationManager#IMPORTANCE_UNSPECIFIED} means that the NAS has not recommended
|
||||
* a change to the importance, and no UI should be shown to the user. See
|
||||
* {@link Adjustment#KEY_IMPORTANCE_PROPOSAL}.
|
||||
*
|
||||
* @return the importance of the notification
|
||||
* @hide
|
||||
*/
|
||||
public @NotificationManager.Importance int getProposedImportance() {
|
||||
return mProposedImportance;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the system has overridden the group key, then this will be non-null, and this
|
||||
* key should be used to bundle notifications.
|
||||
@@ -2041,7 +2061,7 @@ public abstract class NotificationListenerService extends Service {
|
||||
boolean noisy, ArrayList<Notification.Action> smartActions,
|
||||
ArrayList<CharSequence> smartReplies, boolean canBubble,
|
||||
boolean isTextChanged, boolean isConversation, ShortcutInfo shortcutInfo,
|
||||
int rankingAdjustment, boolean isBubble) {
|
||||
int rankingAdjustment, boolean isBubble, int proposedImportance) {
|
||||
mKey = key;
|
||||
mRank = rank;
|
||||
mIsAmbient = importance < NotificationManager.IMPORTANCE_LOW;
|
||||
@@ -2067,6 +2087,7 @@ public abstract class NotificationListenerService extends Service {
|
||||
mShortcutInfo = shortcutInfo;
|
||||
mRankingAdjustment = rankingAdjustment;
|
||||
mIsBubble = isBubble;
|
||||
mProposedImportance = proposedImportance;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2107,7 +2128,8 @@ public abstract class NotificationListenerService extends Service {
|
||||
other.mIsConversation,
|
||||
other.mShortcutInfo,
|
||||
other.mRankingAdjustment,
|
||||
other.mIsBubble);
|
||||
other.mIsBubble,
|
||||
other.mProposedImportance);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2166,7 +2188,8 @@ public abstract class NotificationListenerService extends Service {
|
||||
&& Objects.equals((mShortcutInfo == null ? 0 : mShortcutInfo.getId()),
|
||||
(other.mShortcutInfo == null ? 0 : other.mShortcutInfo.getId()))
|
||||
&& Objects.equals(mRankingAdjustment, other.mRankingAdjustment)
|
||||
&& Objects.equals(mIsBubble, other.mIsBubble);
|
||||
&& Objects.equals(mIsBubble, other.mIsBubble)
|
||||
&& Objects.equals(mProposedImportance, other.mProposedImportance);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -290,7 +290,8 @@ public class NotificationListener extends NotificationListenerWithPlugins implem
|
||||
false,
|
||||
null,
|
||||
0,
|
||||
false
|
||||
false,
|
||||
0
|
||||
);
|
||||
}
|
||||
return ranking;
|
||||
|
||||
@@ -127,6 +127,6 @@ class TargetSdkResolverTest : SysuiTestCase() {
|
||||
NotificationManager.IMPORTANCE_DEFAULT,
|
||||
null, null,
|
||||
null, null, null, true, 0, false, -1, false, null, null, false, false,
|
||||
false, null, 0, false)
|
||||
false, null, 0, false, 0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.systemui.statusbar;
|
||||
|
||||
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
@@ -57,6 +59,7 @@ public class RankingBuilder {
|
||||
private ShortcutInfo mShortcutInfo = null;
|
||||
private int mRankingAdjustment = 0;
|
||||
private boolean mIsBubble = false;
|
||||
private int mProposedImportance = IMPORTANCE_UNSPECIFIED;
|
||||
|
||||
public RankingBuilder() {
|
||||
}
|
||||
@@ -86,6 +89,7 @@ public class RankingBuilder {
|
||||
mShortcutInfo = ranking.getConversationShortcutInfo();
|
||||
mRankingAdjustment = ranking.getRankingAdjustment();
|
||||
mIsBubble = ranking.isBubble();
|
||||
mProposedImportance = ranking.getProposedImportance();
|
||||
}
|
||||
|
||||
public Ranking build() {
|
||||
@@ -114,7 +118,8 @@ public class RankingBuilder {
|
||||
mIsConversation,
|
||||
mShortcutInfo,
|
||||
mRankingAdjustment,
|
||||
mIsBubble);
|
||||
mIsBubble,
|
||||
mProposedImportance);
|
||||
return ranking;
|
||||
}
|
||||
|
||||
@@ -214,6 +219,11 @@ public class RankingBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public RankingBuilder setProposedImportance(@Importance int importance) {
|
||||
mProposedImportance = importance;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RankingBuilder setUserSentiment(int userSentiment) {
|
||||
mUserSentiment = userSentiment;
|
||||
return this;
|
||||
|
||||
@@ -239,7 +239,6 @@ import android.service.notification.NotificationRankingUpdate;
|
||||
import android.service.notification.NotificationRecordProto;
|
||||
import android.service.notification.NotificationServiceDumpProto;
|
||||
import android.service.notification.NotificationStats;
|
||||
import android.service.notification.SnoozeCriterion;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.service.notification.ZenModeConfig;
|
||||
import android.service.notification.ZenModeProto;
|
||||
@@ -8526,95 +8525,6 @@ public class NotificationManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
static class NotificationRecordExtractorData {
|
||||
// Class that stores any field in a NotificationRecord that can change via an extractor.
|
||||
// Used to cache previous data used in a sort.
|
||||
int mPosition;
|
||||
int mVisibility;
|
||||
boolean mShowBadge;
|
||||
boolean mAllowBubble;
|
||||
boolean mIsBubble;
|
||||
NotificationChannel mChannel;
|
||||
String mGroupKey;
|
||||
ArrayList<String> mOverridePeople;
|
||||
ArrayList<SnoozeCriterion> mSnoozeCriteria;
|
||||
Integer mUserSentiment;
|
||||
Integer mSuppressVisually;
|
||||
ArrayList<Notification.Action> mSystemSmartActions;
|
||||
ArrayList<CharSequence> mSmartReplies;
|
||||
int mImportance;
|
||||
|
||||
// These fields may not trigger a reranking but diffs here may be logged.
|
||||
float mRankingScore;
|
||||
boolean mIsConversation;
|
||||
|
||||
NotificationRecordExtractorData(int position, int visibility, boolean showBadge,
|
||||
boolean allowBubble, boolean isBubble, NotificationChannel channel, String groupKey,
|
||||
ArrayList<String> overridePeople, ArrayList<SnoozeCriterion> snoozeCriteria,
|
||||
Integer userSentiment, Integer suppressVisually,
|
||||
ArrayList<Notification.Action> systemSmartActions,
|
||||
ArrayList<CharSequence> smartReplies, int importance, float rankingScore,
|
||||
boolean isConversation) {
|
||||
mPosition = position;
|
||||
mVisibility = visibility;
|
||||
mShowBadge = showBadge;
|
||||
mAllowBubble = allowBubble;
|
||||
mIsBubble = isBubble;
|
||||
mChannel = channel;
|
||||
mGroupKey = groupKey;
|
||||
mOverridePeople = overridePeople;
|
||||
mSnoozeCriteria = snoozeCriteria;
|
||||
mUserSentiment = userSentiment;
|
||||
mSuppressVisually = suppressVisually;
|
||||
mSystemSmartActions = systemSmartActions;
|
||||
mSmartReplies = smartReplies;
|
||||
mImportance = importance;
|
||||
mRankingScore = rankingScore;
|
||||
mIsConversation = isConversation;
|
||||
}
|
||||
|
||||
// Returns whether the provided NotificationRecord differs from the cached data in any way.
|
||||
// Should be guarded by mNotificationLock; not annotated here as this class is static.
|
||||
boolean hasDiffForRankingLocked(NotificationRecord r, int newPosition) {
|
||||
return mPosition != newPosition
|
||||
|| mVisibility != r.getPackageVisibilityOverride()
|
||||
|| mShowBadge != r.canShowBadge()
|
||||
|| mAllowBubble != r.canBubble()
|
||||
|| mIsBubble != r.getNotification().isBubbleNotification()
|
||||
|| !Objects.equals(mChannel, r.getChannel())
|
||||
|| !Objects.equals(mGroupKey, r.getGroupKey())
|
||||
|| !Objects.equals(mOverridePeople, r.getPeopleOverride())
|
||||
|| !Objects.equals(mSnoozeCriteria, r.getSnoozeCriteria())
|
||||
|| !Objects.equals(mUserSentiment, r.getUserSentiment())
|
||||
|| !Objects.equals(mSuppressVisually, r.getSuppressedVisualEffects())
|
||||
|| !Objects.equals(mSystemSmartActions, r.getSystemGeneratedSmartActions())
|
||||
|| !Objects.equals(mSmartReplies, r.getSmartReplies())
|
||||
|| mImportance != r.getImportance();
|
||||
}
|
||||
|
||||
// Returns whether the NotificationRecord has a change from this data for which we should
|
||||
// log an update. This method specifically targets fields that may be changed via
|
||||
// adjustments from the assistant.
|
||||
//
|
||||
// Fields here are the union of things in NotificationRecordLogger.shouldLogReported
|
||||
// and NotificationRecord.applyAdjustments.
|
||||
//
|
||||
// Should be guarded by mNotificationLock; not annotated here as this class is static.
|
||||
boolean hasDiffForLoggingLocked(NotificationRecord r, int newPosition) {
|
||||
return mPosition != newPosition
|
||||
|| !Objects.equals(mChannel, r.getChannel())
|
||||
|| !Objects.equals(mGroupKey, r.getGroupKey())
|
||||
|| !Objects.equals(mOverridePeople, r.getPeopleOverride())
|
||||
|| !Objects.equals(mSnoozeCriteria, r.getSnoozeCriteria())
|
||||
|| !Objects.equals(mUserSentiment, r.getUserSentiment())
|
||||
|| !Objects.equals(mSystemSmartActions, r.getSystemGeneratedSmartActions())
|
||||
|| !Objects.equals(mSmartReplies, r.getSmartReplies())
|
||||
|| mImportance != r.getImportance()
|
||||
|| !r.rankingScoreMatches(mRankingScore)
|
||||
|| mIsConversation != r.isConversation();
|
||||
}
|
||||
}
|
||||
|
||||
void handleRankingSort() {
|
||||
if (mRankingHelper == null) return;
|
||||
synchronized (mNotificationLock) {
|
||||
@@ -8640,7 +8550,8 @@ public class NotificationManagerService extends SystemService {
|
||||
r.getSmartReplies(),
|
||||
r.getImportance(),
|
||||
r.getRankingScore(),
|
||||
r.isConversation());
|
||||
r.isConversation(),
|
||||
r.getProposedImportance());
|
||||
extractorDataBefore.put(r.getKey(), extractorData);
|
||||
mRankingHelper.extractSignals(r);
|
||||
}
|
||||
@@ -9935,7 +9846,8 @@ public class NotificationManagerService extends SystemService {
|
||||
record.getRankingScore() == 0
|
||||
? RANKING_UNCHANGED
|
||||
: (record.getRankingScore() > 0 ? RANKING_PROMOTED : RANKING_DEMOTED),
|
||||
record.getNotification().isBubbleNotification()
|
||||
record.getNotification().isBubbleNotification(),
|
||||
record.getProposedImportance()
|
||||
);
|
||||
rankings.add(ranking);
|
||||
}
|
||||
|
||||
@@ -210,6 +210,7 @@ public final class NotificationRecord {
|
||||
// Whether this notification record should have an update logged the next time notifications
|
||||
// are sorted.
|
||||
private boolean mPendingLogUpdate = false;
|
||||
private int mProposedImportance = IMPORTANCE_UNSPECIFIED;
|
||||
|
||||
public NotificationRecord(Context context, StatusBarNotification sbn,
|
||||
NotificationChannel channel) {
|
||||
@@ -499,6 +500,8 @@ public final class NotificationRecord {
|
||||
pw.println(prefix + "mImportance="
|
||||
+ NotificationListenerService.Ranking.importanceToString(mImportance));
|
||||
pw.println(prefix + "mImportanceExplanation=" + getImportanceExplanation());
|
||||
pw.println(prefix + "mProposedImportance="
|
||||
+ NotificationListenerService.Ranking.importanceToString(mProposedImportance));
|
||||
pw.println(prefix + "mIsAppImportanceLocked=" + mIsAppImportanceLocked);
|
||||
pw.println(prefix + "mIntercept=" + mIntercept);
|
||||
pw.println(prefix + "mHidden==" + mHidden);
|
||||
@@ -738,6 +741,12 @@ public final class NotificationRecord {
|
||||
Adjustment.KEY_NOT_CONVERSATION,
|
||||
Boolean.toString(mIsNotConversationOverride));
|
||||
}
|
||||
if (signals.containsKey(Adjustment.KEY_IMPORTANCE_PROPOSAL)) {
|
||||
mProposedImportance = signals.getInt(Adjustment.KEY_IMPORTANCE_PROPOSAL);
|
||||
EventLogTags.writeNotificationAdjusted(getKey(),
|
||||
Adjustment.KEY_IMPORTANCE_PROPOSAL,
|
||||
Integer.toString(mProposedImportance));
|
||||
}
|
||||
if (!signals.isEmpty() && adjustment.getIssuer() != null) {
|
||||
mAdjustmentIssuer = adjustment.getIssuer();
|
||||
}
|
||||
@@ -870,6 +879,10 @@ public final class NotificationRecord {
|
||||
return stats.naturalImportance;
|
||||
}
|
||||
|
||||
public int getProposedImportance() {
|
||||
return mProposedImportance;
|
||||
}
|
||||
|
||||
public float getRankingScore() {
|
||||
return mRankingScore;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.android.server.notification;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.service.notification.SnoozeCriterion;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Class that stores any field in a NotificationRecord that can change via an extractor.
|
||||
* Used to cache previous data used in a sort.
|
||||
*/
|
||||
public final class NotificationRecordExtractorData {
|
||||
private final int mPosition;
|
||||
private final int mVisibility;
|
||||
private final boolean mShowBadge;
|
||||
private final boolean mAllowBubble;
|
||||
private final boolean mIsBubble;
|
||||
private final NotificationChannel mChannel;
|
||||
private final String mGroupKey;
|
||||
private final ArrayList<String> mOverridePeople;
|
||||
private final ArrayList<SnoozeCriterion> mSnoozeCriteria;
|
||||
private final Integer mUserSentiment;
|
||||
private final Integer mSuppressVisually;
|
||||
private final ArrayList<Notification.Action> mSystemSmartActions;
|
||||
private final ArrayList<CharSequence> mSmartReplies;
|
||||
private final int mImportance;
|
||||
|
||||
// These fields may not trigger a reranking but diffs here may be logged.
|
||||
private final float mRankingScore;
|
||||
private final boolean mIsConversation;
|
||||
private final int mProposedImportance;
|
||||
|
||||
NotificationRecordExtractorData(int position, int visibility, boolean showBadge,
|
||||
boolean allowBubble, boolean isBubble, NotificationChannel channel, String groupKey,
|
||||
ArrayList<String> overridePeople, ArrayList<SnoozeCriterion> snoozeCriteria,
|
||||
Integer userSentiment, Integer suppressVisually,
|
||||
ArrayList<Notification.Action> systemSmartActions,
|
||||
ArrayList<CharSequence> smartReplies, int importance, float rankingScore,
|
||||
boolean isConversation, int proposedImportance) {
|
||||
mPosition = position;
|
||||
mVisibility = visibility;
|
||||
mShowBadge = showBadge;
|
||||
mAllowBubble = allowBubble;
|
||||
mIsBubble = isBubble;
|
||||
mChannel = channel;
|
||||
mGroupKey = groupKey;
|
||||
mOverridePeople = overridePeople;
|
||||
mSnoozeCriteria = snoozeCriteria;
|
||||
mUserSentiment = userSentiment;
|
||||
mSuppressVisually = suppressVisually;
|
||||
mSystemSmartActions = systemSmartActions;
|
||||
mSmartReplies = smartReplies;
|
||||
mImportance = importance;
|
||||
mRankingScore = rankingScore;
|
||||
mIsConversation = isConversation;
|
||||
mProposedImportance = proposedImportance;
|
||||
}
|
||||
|
||||
// Returns whether the provided NotificationRecord differs from the cached data in any way.
|
||||
// Should be guarded by mNotificationLock; not annotated here as this class is static.
|
||||
boolean hasDiffForRankingLocked(NotificationRecord r, int newPosition) {
|
||||
return mPosition != newPosition
|
||||
|| mVisibility != r.getPackageVisibilityOverride()
|
||||
|| mShowBadge != r.canShowBadge()
|
||||
|| mAllowBubble != r.canBubble()
|
||||
|| mIsBubble != r.getNotification().isBubbleNotification()
|
||||
|| !Objects.equals(mChannel, r.getChannel())
|
||||
|| !Objects.equals(mGroupKey, r.getGroupKey())
|
||||
|| !Objects.equals(mOverridePeople, r.getPeopleOverride())
|
||||
|| !Objects.equals(mSnoozeCriteria, r.getSnoozeCriteria())
|
||||
|| !Objects.equals(mUserSentiment, r.getUserSentiment())
|
||||
|| !Objects.equals(mSuppressVisually, r.getSuppressedVisualEffects())
|
||||
|| !Objects.equals(mSystemSmartActions, r.getSystemGeneratedSmartActions())
|
||||
|| !Objects.equals(mSmartReplies, r.getSmartReplies())
|
||||
|| mImportance != r.getImportance()
|
||||
|| mProposedImportance != r.getProposedImportance();
|
||||
}
|
||||
|
||||
// Returns whether the NotificationRecord has a change from this data for which we should
|
||||
// log an update. This method specifically targets fields that may be changed via
|
||||
// adjustments from the assistant.
|
||||
//
|
||||
// Fields here are the union of things in NotificationRecordLogger.shouldLogReported
|
||||
// and NotificationRecord.applyAdjustments.
|
||||
//
|
||||
// Should be guarded by mNotificationLock; not annotated here as this class is static.
|
||||
boolean hasDiffForLoggingLocked(NotificationRecord r, int newPosition) {
|
||||
return mPosition != newPosition
|
||||
|| !Objects.equals(mChannel, r.getChannel())
|
||||
|| !Objects.equals(mGroupKey, r.getGroupKey())
|
||||
|| !Objects.equals(mOverridePeople, r.getPeopleOverride())
|
||||
|| !Objects.equals(mSnoozeCriteria, r.getSnoozeCriteria())
|
||||
|| !Objects.equals(mUserSentiment, r.getUserSentiment())
|
||||
|| !Objects.equals(mSystemSmartActions, r.getSystemGeneratedSmartActions())
|
||||
|| !Objects.equals(mSmartReplies, r.getSmartReplies())
|
||||
|| mImportance != r.getImportance()
|
||||
|| !r.rankingScoreMatches(mRankingScore)
|
||||
|| mIsConversation != r.isConversation()
|
||||
|| mProposedImportance != r.getProposedImportance();
|
||||
}
|
||||
}
|
||||
@@ -1678,7 +1678,7 @@ public final class DataManagerTest {
|
||||
mParentNotificationChannel.getImportance(),
|
||||
null, null,
|
||||
mParentNotificationChannel, null, null, true, 0, false, -1, false, null, null,
|
||||
false, false, false, null, 0, false);
|
||||
false, false, false, null, 0, false, 0);
|
||||
return true;
|
||||
}).when(mRankingMap).getRanking(eq(GENERIC_KEY),
|
||||
any(NotificationListenerService.Ranking.class));
|
||||
@@ -1704,7 +1704,7 @@ public final class DataManagerTest {
|
||||
mNotificationChannel.getImportance(),
|
||||
null, null,
|
||||
mNotificationChannel, null, null, true, 0, false, -1, false, null, null, false,
|
||||
false, false, null, 0, false);
|
||||
false, false, null, 0, false, 0);
|
||||
return true;
|
||||
}).when(mRankingMap).getRanking(eq(CUSTOM_KEY),
|
||||
any(NotificationListenerService.Ranking.class));
|
||||
|
||||
@@ -193,7 +193,8 @@ public class NotificationListenerServiceTest extends UiServiceTestCase {
|
||||
tweak.isConversation(),
|
||||
tweak.getConversationShortcutInfo(),
|
||||
tweak.getRankingAdjustment(),
|
||||
tweak.isBubble()
|
||||
tweak.isBubble(),
|
||||
tweak.getProposedImportance()
|
||||
);
|
||||
assertNotEquals(nru, nru2);
|
||||
}
|
||||
@@ -274,7 +275,8 @@ public class NotificationListenerServiceTest extends UiServiceTestCase {
|
||||
isConversation(i),
|
||||
getShortcutInfo(i),
|
||||
getRankingAdjustment(i),
|
||||
isBubble(i)
|
||||
isBubble(i),
|
||||
getProposedImportance(i)
|
||||
);
|
||||
rankings[i] = ranking;
|
||||
}
|
||||
@@ -402,6 +404,10 @@ public class NotificationListenerServiceTest extends UiServiceTestCase {
|
||||
return index % 3 - 1;
|
||||
}
|
||||
|
||||
private int getProposedImportance(int index) {
|
||||
return index % 5 - 1;
|
||||
}
|
||||
|
||||
private boolean isBubble(int index) {
|
||||
return index % 4 == 0;
|
||||
}
|
||||
@@ -443,6 +449,7 @@ public class NotificationListenerServiceTest extends UiServiceTestCase {
|
||||
assertEquals(comment, a.getConversationShortcutInfo().getId(),
|
||||
b.getConversationShortcutInfo().getId());
|
||||
assertActionsEqual(a.getSmartActions(), b.getSmartActions());
|
||||
assertEquals(a.getProposedImportance(), b.getProposedImportance());
|
||||
}
|
||||
|
||||
private void detailedAssertEquals(RankingMap a, RankingMap b) {
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.server.notification;
|
||||
|
||||
import static android.app.NotificationManager.IMPORTANCE_HIGH;
|
||||
import static android.app.NotificationManager.IMPORTANCE_LOW;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertFalse;
|
||||
import static junit.framework.Assert.assertNull;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
import android.service.notification.Adjustment;
|
||||
import android.service.notification.SnoozeCriterion;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
|
||||
import com.android.server.UiServiceTestCase;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Objects;
|
||||
|
||||
public class NotificationRecordExtractorDataTest extends UiServiceTestCase {
|
||||
|
||||
@Test
|
||||
public void testHasDiffs_noDiffs() {
|
||||
NotificationRecord r = generateRecord();
|
||||
|
||||
NotificationRecordExtractorData extractorData = new NotificationRecordExtractorData(
|
||||
1,
|
||||
r.getPackageVisibilityOverride(),
|
||||
r.canShowBadge(),
|
||||
r.canBubble(),
|
||||
r.getNotification().isBubbleNotification(),
|
||||
r.getChannel(),
|
||||
r.getGroupKey(),
|
||||
r.getPeopleOverride(),
|
||||
r.getSnoozeCriteria(),
|
||||
r.getUserSentiment(),
|
||||
r.getSuppressedVisualEffects(),
|
||||
r.getSystemGeneratedSmartActions(),
|
||||
r.getSmartReplies(),
|
||||
r.getImportance(),
|
||||
r.getRankingScore(),
|
||||
r.isConversation(),
|
||||
r.getProposedImportance());
|
||||
|
||||
assertFalse(extractorData.hasDiffForRankingLocked(r, 1));
|
||||
assertFalse(extractorData.hasDiffForLoggingLocked(r, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHasDiffs_proposedImportanceChange() {
|
||||
NotificationRecord r = generateRecord();
|
||||
|
||||
NotificationRecordExtractorData extractorData = new NotificationRecordExtractorData(
|
||||
1,
|
||||
r.getPackageVisibilityOverride(),
|
||||
r.canShowBadge(),
|
||||
r.canBubble(),
|
||||
r.getNotification().isBubbleNotification(),
|
||||
r.getChannel(),
|
||||
r.getGroupKey(),
|
||||
r.getPeopleOverride(),
|
||||
r.getSnoozeCriteria(),
|
||||
r.getUserSentiment(),
|
||||
r.getSuppressedVisualEffects(),
|
||||
r.getSystemGeneratedSmartActions(),
|
||||
r.getSmartReplies(),
|
||||
r.getImportance(),
|
||||
r.getRankingScore(),
|
||||
r.isConversation(),
|
||||
r.getProposedImportance());
|
||||
|
||||
Bundle signals = new Bundle();
|
||||
signals.putInt(Adjustment.KEY_IMPORTANCE_PROPOSAL, IMPORTANCE_HIGH);
|
||||
Adjustment adjustment = new Adjustment("pkg", r.getKey(), signals, "", 0);
|
||||
r.addAdjustment(adjustment);
|
||||
r.applyAdjustments();
|
||||
|
||||
assertTrue(extractorData.hasDiffForRankingLocked(r, 1));
|
||||
assertTrue(extractorData.hasDiffForLoggingLocked(r, 1));
|
||||
}
|
||||
|
||||
private NotificationRecord generateRecord() {
|
||||
NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW);
|
||||
final Notification.Builder builder = new Notification.Builder(getContext())
|
||||
.setContentTitle("foo")
|
||||
.setSmallIcon(android.R.drawable.sym_def_app_icon);
|
||||
Notification n = builder.build();
|
||||
StatusBarNotification sbn = new StatusBarNotification("", "", 0, "", 0,
|
||||
0, n, UserHandle.ALL, null, System.currentTimeMillis());
|
||||
return new NotificationRecord(getContext(), sbn, channel);
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE;
|
||||
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
|
||||
import static android.app.NotificationManager.IMPORTANCE_HIGH;
|
||||
import static android.app.NotificationManager.IMPORTANCE_LOW;
|
||||
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
|
||||
import static android.service.notification.Adjustment.KEY_IMPORTANCE;
|
||||
import static android.service.notification.Adjustment.KEY_NOT_CONVERSATION;
|
||||
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
|
||||
@@ -754,6 +755,24 @@ public class NotificationRecordTest extends UiServiceTestCase {
|
||||
assertEquals(USER_SENTIMENT_POSITIVE, record.getUserSentiment());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProposedImportance() {
|
||||
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);
|
||||
|
||||
assertEquals(IMPORTANCE_UNSPECIFIED, record.getProposedImportance());
|
||||
|
||||
Bundle signals = new Bundle();
|
||||
signals.putInt(Adjustment.KEY_IMPORTANCE_PROPOSAL, IMPORTANCE_DEFAULT);
|
||||
record.addAdjustment(new Adjustment(mPkg, record.getKey(), signals, null, sbn.getUserId()));
|
||||
|
||||
record.applyAdjustments();
|
||||
|
||||
assertEquals(IMPORTANCE_DEFAULT, record.getProposedImportance());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAppImportance_returnsCorrectly() {
|
||||
StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
|
||||
|
||||
Reference in New Issue
Block a user