Loading core/java/android/service/notification/StatusBarNotification.java +23 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ public class StatusBarNotification implements Parcelable { private final int id; private final String tag; private final String key; private final String groupKey; private final int uid; private final String opPkg; Loading Loading @@ -65,6 +66,7 @@ public class StatusBarNotification implements Parcelable { this.notification.setUser(user); this.postTime = postTime; this.key = key(); this.groupKey = groupKey(); } public StatusBarNotification(Parcel in) { Loading @@ -84,12 +86,26 @@ public class StatusBarNotification implements Parcelable { this.notification.setUser(this.user); this.postTime = in.readLong(); this.key = key(); this.groupKey = groupKey(); } private String key() { return user.getIdentifier() + "|" + pkg + "|" + id + "|" + tag + "|" + uid; } private String groupKey() { final String group = getNotification().getGroup(); final String sortKey = getNotification().getSortKey(); if (group == null && sortKey == null) { // a group of one return key; } return user.getIdentifier() + "|" + pkg + "|" + (group == null ? "p:" + notification.priority : "g:" + group); } public void writeToParcel(Parcel out, int flags) { out.writeString(this.pkg); out.writeString(this.opPkg); Loading Loading @@ -240,4 +256,11 @@ public class StatusBarNotification implements Parcelable { public String getKey() { return key; } /** * A key that indicates the group with which this message ranks. */ public String getGroupKey() { return groupKey; } } services/core/java/com/android/server/notification/GroupedNotificationComparator.java 0 → 100644 +57 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 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.text.TextUtils; import android.util.Log; /** * Sorts notifications, accounting for groups and sort keys. */ public class GroupedNotificationComparator extends NotificationComparator { private static final String TAG = "GroupedNotificationComparator"; @Override public int compare(NotificationRecord left, NotificationRecord right) { // "recently intrusive" is an ad hoc group that temporarily claims noisy notifications if (left.isRecentlyIntrusive() != right.isRecentlyIntrusive()) { return left.isRecentlyIntrusive() ? -1 : 1; } final NotificationRecord leftProxy = left.getRankingProxy(); if (leftProxy == null) { throw new RuntimeException("left proxy cannot be null: " + left.getKey()); } final NotificationRecord rightProxy = right.getRankingProxy(); if (rightProxy == null) { throw new RuntimeException("right proxy cannot be null: " + right.getKey()); } final String leftSortKey = left.getNotification().getSortKey(); final String rightSortKey = right.getNotification().getSortKey(); if (leftProxy != rightProxy) { // between groups, compare proxies return Integer.compare(leftProxy.getAuthoritativeRank(), rightProxy.getAuthoritativeRank()); } else if (TextUtils.isEmpty(leftSortKey) || TextUtils.isEmpty(rightSortKey)) { // missing sort keys, use prior rank return Integer.compare(left.getAuthoritativeRank(), right.getAuthoritativeRank()); } else { // use sort keys within group return leftSortKey.compareTo(rightSortKey); } } } services/core/java/com/android/server/notification/NotificationComparator.java +14 −14 Original line number Diff line number Diff line Loading @@ -18,35 +18,35 @@ package com.android.server.notification; import java.util.Comparator; /** * Sorts notificaitons into attention-relelvant order. * Sorts notifications individually into attention-relelvant order. */ public class NotificationComparator implements Comparator<NotificationRecord> { @Override public int compare(NotificationRecord lhs, NotificationRecord rhs) { if (lhs.isRecentlyIntrusive() != rhs.isRecentlyIntrusive()) { return lhs.isRecentlyIntrusive() ? -1 : 1; } final int leftPackagePriority = lhs.getPackagePriority(); final int rightPackagePriority = rhs.getPackagePriority(); public int compare(NotificationRecord left, NotificationRecord right) { final int leftPackagePriority = left.getPackagePriority(); final int rightPackagePriority = right.getPackagePriority(); if (leftPackagePriority != rightPackagePriority) { // by priority, high to low return -1 * Integer.compare(leftPackagePriority, rightPackagePriority); } final int leftScore = lhs.sbn.getScore(); final int rightScore = rhs.sbn.getScore(); final int leftScore = left.sbn.getScore(); final int rightScore = right.sbn.getScore(); if (leftScore != rightScore) { // by priority, high to low return -1 * Integer.compare(leftScore, rightScore); } final float leftPeple = lhs.getContactAffinity(); final float rightPeople = rhs.getContactAffinity(); if (leftPeple != rightPeople) { final float leftPeople = left.getContactAffinity(); final float rightPeople = right.getContactAffinity(); if (leftPeople != rightPeople) { // by contact proximity, close to far return -1 * Float.compare(leftPeple, rightPeople); return -1 * Float.compare(leftPeople, rightPeople); } // then break ties by time, most recent first return -1 * Long.compare(lhs.getRankingTimeMs(), rhs.getRankingTimeMs()); return -1 * Long.compare(left.getRankingTimeMs(), right.getRankingTimeMs()); } } services/core/java/com/android/server/notification/NotificationRecord.java +31 −1 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; import android.graphics.Bitmap; import android.service.notification.StatusBarNotification; import com.android.internal.annotations.VisibleForTesting; import java.io.PrintWriter; import java.lang.reflect.Array; Loading Loading @@ -60,7 +61,12 @@ public final class NotificationRecord { public boolean isUpdate; private int mPackagePriority; NotificationRecord(StatusBarNotification sbn, int score) // The record that ranking should use for comparisons outside the group. private NotificationRecord mRankingProxy; private int mAuthoritativeRank; @VisibleForTesting public NotificationRecord(StatusBarNotification sbn, int score) { this.sbn = sbn; this.score = score; Loading @@ -73,7 +79,9 @@ public final class NotificationRecord { mRecentlyIntrusive = previous.mRecentlyIntrusive; mPackagePriority = previous.mPackagePriority; mIntercept = previous.mIntercept; mRankingProxy = previous.mRankingProxy; mRankingTimeMs = calculateRankingTimeMs(previous.getRankingTimeMs()); // Don't copy mGroupKey, recompute it, in case it has changed } public Notification getNotification() { return sbn.getNotification(); } Loading @@ -89,6 +97,7 @@ public final class NotificationRecord { + " / " + idDebugString(baseContext, sbn.getPackageName(), notification.icon)); pw.println(prefix + " pri=" + notification.priority + " score=" + sbn.getScore()); pw.println(prefix + " key=" + sbn.getKey()); pw.println(prefix + " groupKey=" + getGroupKey()); pw.println(prefix + " contentIntent=" + notification.contentIntent); pw.println(prefix + " deleteIntent=" + notification.deleteIntent); pw.println(prefix + " tickerText=" + notification.tickerText); Loading Loading @@ -145,6 +154,7 @@ public final class NotificationRecord { pw.println(prefix + " mRecentlyIntrusive=" + mRecentlyIntrusive); pw.println(prefix + " mPackagePriority=" + mPackagePriority); pw.println(prefix + " mIntercept=" + mIntercept); pw.println(prefix + " mRankingProxy=" + getRankingProxy().getKey()); pw.println(prefix + " mRankingTimeMs=" + mRankingTimeMs); } Loading Loading @@ -241,4 +251,24 @@ public final class NotificationRecord { } return sbn.getPostTime(); } public NotificationRecord getRankingProxy() { return mRankingProxy; } public void setRankingProxy(NotificationRecord proxy) { mRankingProxy = proxy; } public void setAuthoritativeRank(int authoritativeRank) { mAuthoritativeRank = authoritativeRank; } public int getAuthoritativeRank() { return mAuthoritativeRank; } public String getGroupKey() { return sbn.getGroupKey(); } } services/core/java/com/android/server/notification/RankingHelper.java +35 −6 Original line number Diff line number Diff line Loading @@ -17,12 +17,12 @@ package com.android.server.notification; import android.app.Notification; import android.content.Context; import android.net.Uri; import android.os.Handler; import android.os.Message; import android.os.UserHandle; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; import android.util.Slog; import android.util.SparseIntArray; import org.xmlpull.v1.XmlPullParser; Loading @@ -49,13 +49,13 @@ public class RankingHelper implements RankingConfig { private static final String ATT_UID = "uid"; private static final String ATT_PRIORITY = "priority"; private static final String VALUE_HIGH = "high"; private final NotificationSignalExtractor[] mSignalExtractors; private final NotificationComparator mRankingComparator = new NotificationComparator(); private final NotificationComparator mPreliminaryComparator = new NotificationComparator(); private final NotificationComparator mFinalComparator = new GroupedNotificationComparator(); // Package name to uid, to priority. Would be better as Table<String, Int, Int> private final ArrayMap<String, SparseIntArray> mPackagePriorities; private final ArrayMap<String, NotificationRecord> mProxyByGroupTmp; private final Context mContext; private final Handler mRankingHandler; Loading Loading @@ -83,6 +83,7 @@ public class RankingHelper implements RankingConfig { Slog.w(TAG, "Problem accessing extractor " + extractorNames[i] + ".", e); } } mProxyByGroupTmp = new ArrayMap<String, NotificationRecord>(); } public void extractSignals(NotificationRecord r) { Loading Loading @@ -166,11 +167,39 @@ public class RankingHelper implements RankingConfig { } public void sort(ArrayList<NotificationRecord> notificationList) { Collections.sort(notificationList, mRankingComparator); final int N = notificationList.size(); // clear group proxies for (int i = N - 1; i >= 0; i--) { notificationList.get(i).setRankingProxy(null); } // rank each record individually Collections.sort(notificationList, mPreliminaryComparator); // record inidivdual ranking result and nominate proxies for each group for (int i = N - 1; i >= 0; i--) { final NotificationRecord record = notificationList.get(i); record.setAuthoritativeRank(i); final String groupKey = record.getGroupKey(); boolean isGroupSummary = record.getNotification().getGroup() != null && (record.getNotification().flags & Notification.FLAG_GROUP_SUMMARY) != 0; if (isGroupSummary || mProxyByGroupTmp.get(groupKey) == null) { mProxyByGroupTmp.put(groupKey, record); } } // assign nominated proxies to each notification for (int i = 0; i < N; i++) { final NotificationRecord record = notificationList.get(i); record.setRankingProxy(mProxyByGroupTmp.get(record.getGroupKey())); } // Do a second ranking pass, using group proxies Collections.sort(notificationList, mFinalComparator); mProxyByGroupTmp.clear(); } public int indexOf(ArrayList<NotificationRecord> notificationList, NotificationRecord target) { return Collections.binarySearch(notificationList, target, mRankingComparator); return Collections.binarySearch(notificationList, target, mFinalComparator); } private static int safeInt(XmlPullParser parser, String att, int defValue) { Loading Loading
core/java/android/service/notification/StatusBarNotification.java +23 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ public class StatusBarNotification implements Parcelable { private final int id; private final String tag; private final String key; private final String groupKey; private final int uid; private final String opPkg; Loading Loading @@ -65,6 +66,7 @@ public class StatusBarNotification implements Parcelable { this.notification.setUser(user); this.postTime = postTime; this.key = key(); this.groupKey = groupKey(); } public StatusBarNotification(Parcel in) { Loading @@ -84,12 +86,26 @@ public class StatusBarNotification implements Parcelable { this.notification.setUser(this.user); this.postTime = in.readLong(); this.key = key(); this.groupKey = groupKey(); } private String key() { return user.getIdentifier() + "|" + pkg + "|" + id + "|" + tag + "|" + uid; } private String groupKey() { final String group = getNotification().getGroup(); final String sortKey = getNotification().getSortKey(); if (group == null && sortKey == null) { // a group of one return key; } return user.getIdentifier() + "|" + pkg + "|" + (group == null ? "p:" + notification.priority : "g:" + group); } public void writeToParcel(Parcel out, int flags) { out.writeString(this.pkg); out.writeString(this.opPkg); Loading Loading @@ -240,4 +256,11 @@ public class StatusBarNotification implements Parcelable { public String getKey() { return key; } /** * A key that indicates the group with which this message ranks. */ public String getGroupKey() { return groupKey; } }
services/core/java/com/android/server/notification/GroupedNotificationComparator.java 0 → 100644 +57 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 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.text.TextUtils; import android.util.Log; /** * Sorts notifications, accounting for groups and sort keys. */ public class GroupedNotificationComparator extends NotificationComparator { private static final String TAG = "GroupedNotificationComparator"; @Override public int compare(NotificationRecord left, NotificationRecord right) { // "recently intrusive" is an ad hoc group that temporarily claims noisy notifications if (left.isRecentlyIntrusive() != right.isRecentlyIntrusive()) { return left.isRecentlyIntrusive() ? -1 : 1; } final NotificationRecord leftProxy = left.getRankingProxy(); if (leftProxy == null) { throw new RuntimeException("left proxy cannot be null: " + left.getKey()); } final NotificationRecord rightProxy = right.getRankingProxy(); if (rightProxy == null) { throw new RuntimeException("right proxy cannot be null: " + right.getKey()); } final String leftSortKey = left.getNotification().getSortKey(); final String rightSortKey = right.getNotification().getSortKey(); if (leftProxy != rightProxy) { // between groups, compare proxies return Integer.compare(leftProxy.getAuthoritativeRank(), rightProxy.getAuthoritativeRank()); } else if (TextUtils.isEmpty(leftSortKey) || TextUtils.isEmpty(rightSortKey)) { // missing sort keys, use prior rank return Integer.compare(left.getAuthoritativeRank(), right.getAuthoritativeRank()); } else { // use sort keys within group return leftSortKey.compareTo(rightSortKey); } } }
services/core/java/com/android/server/notification/NotificationComparator.java +14 −14 Original line number Diff line number Diff line Loading @@ -18,35 +18,35 @@ package com.android.server.notification; import java.util.Comparator; /** * Sorts notificaitons into attention-relelvant order. * Sorts notifications individually into attention-relelvant order. */ public class NotificationComparator implements Comparator<NotificationRecord> { @Override public int compare(NotificationRecord lhs, NotificationRecord rhs) { if (lhs.isRecentlyIntrusive() != rhs.isRecentlyIntrusive()) { return lhs.isRecentlyIntrusive() ? -1 : 1; } final int leftPackagePriority = lhs.getPackagePriority(); final int rightPackagePriority = rhs.getPackagePriority(); public int compare(NotificationRecord left, NotificationRecord right) { final int leftPackagePriority = left.getPackagePriority(); final int rightPackagePriority = right.getPackagePriority(); if (leftPackagePriority != rightPackagePriority) { // by priority, high to low return -1 * Integer.compare(leftPackagePriority, rightPackagePriority); } final int leftScore = lhs.sbn.getScore(); final int rightScore = rhs.sbn.getScore(); final int leftScore = left.sbn.getScore(); final int rightScore = right.sbn.getScore(); if (leftScore != rightScore) { // by priority, high to low return -1 * Integer.compare(leftScore, rightScore); } final float leftPeple = lhs.getContactAffinity(); final float rightPeople = rhs.getContactAffinity(); if (leftPeple != rightPeople) { final float leftPeople = left.getContactAffinity(); final float rightPeople = right.getContactAffinity(); if (leftPeople != rightPeople) { // by contact proximity, close to far return -1 * Float.compare(leftPeple, rightPeople); return -1 * Float.compare(leftPeople, rightPeople); } // then break ties by time, most recent first return -1 * Long.compare(lhs.getRankingTimeMs(), rhs.getRankingTimeMs()); return -1 * Long.compare(left.getRankingTimeMs(), right.getRankingTimeMs()); } }
services/core/java/com/android/server/notification/NotificationRecord.java +31 −1 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; import android.graphics.Bitmap; import android.service.notification.StatusBarNotification; import com.android.internal.annotations.VisibleForTesting; import java.io.PrintWriter; import java.lang.reflect.Array; Loading Loading @@ -60,7 +61,12 @@ public final class NotificationRecord { public boolean isUpdate; private int mPackagePriority; NotificationRecord(StatusBarNotification sbn, int score) // The record that ranking should use for comparisons outside the group. private NotificationRecord mRankingProxy; private int mAuthoritativeRank; @VisibleForTesting public NotificationRecord(StatusBarNotification sbn, int score) { this.sbn = sbn; this.score = score; Loading @@ -73,7 +79,9 @@ public final class NotificationRecord { mRecentlyIntrusive = previous.mRecentlyIntrusive; mPackagePriority = previous.mPackagePriority; mIntercept = previous.mIntercept; mRankingProxy = previous.mRankingProxy; mRankingTimeMs = calculateRankingTimeMs(previous.getRankingTimeMs()); // Don't copy mGroupKey, recompute it, in case it has changed } public Notification getNotification() { return sbn.getNotification(); } Loading @@ -89,6 +97,7 @@ public final class NotificationRecord { + " / " + idDebugString(baseContext, sbn.getPackageName(), notification.icon)); pw.println(prefix + " pri=" + notification.priority + " score=" + sbn.getScore()); pw.println(prefix + " key=" + sbn.getKey()); pw.println(prefix + " groupKey=" + getGroupKey()); pw.println(prefix + " contentIntent=" + notification.contentIntent); pw.println(prefix + " deleteIntent=" + notification.deleteIntent); pw.println(prefix + " tickerText=" + notification.tickerText); Loading Loading @@ -145,6 +154,7 @@ public final class NotificationRecord { pw.println(prefix + " mRecentlyIntrusive=" + mRecentlyIntrusive); pw.println(prefix + " mPackagePriority=" + mPackagePriority); pw.println(prefix + " mIntercept=" + mIntercept); pw.println(prefix + " mRankingProxy=" + getRankingProxy().getKey()); pw.println(prefix + " mRankingTimeMs=" + mRankingTimeMs); } Loading Loading @@ -241,4 +251,24 @@ public final class NotificationRecord { } return sbn.getPostTime(); } public NotificationRecord getRankingProxy() { return mRankingProxy; } public void setRankingProxy(NotificationRecord proxy) { mRankingProxy = proxy; } public void setAuthoritativeRank(int authoritativeRank) { mAuthoritativeRank = authoritativeRank; } public int getAuthoritativeRank() { return mAuthoritativeRank; } public String getGroupKey() { return sbn.getGroupKey(); } }
services/core/java/com/android/server/notification/RankingHelper.java +35 −6 Original line number Diff line number Diff line Loading @@ -17,12 +17,12 @@ package com.android.server.notification; import android.app.Notification; import android.content.Context; import android.net.Uri; import android.os.Handler; import android.os.Message; import android.os.UserHandle; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; import android.util.Slog; import android.util.SparseIntArray; import org.xmlpull.v1.XmlPullParser; Loading @@ -49,13 +49,13 @@ public class RankingHelper implements RankingConfig { private static final String ATT_UID = "uid"; private static final String ATT_PRIORITY = "priority"; private static final String VALUE_HIGH = "high"; private final NotificationSignalExtractor[] mSignalExtractors; private final NotificationComparator mRankingComparator = new NotificationComparator(); private final NotificationComparator mPreliminaryComparator = new NotificationComparator(); private final NotificationComparator mFinalComparator = new GroupedNotificationComparator(); // Package name to uid, to priority. Would be better as Table<String, Int, Int> private final ArrayMap<String, SparseIntArray> mPackagePriorities; private final ArrayMap<String, NotificationRecord> mProxyByGroupTmp; private final Context mContext; private final Handler mRankingHandler; Loading Loading @@ -83,6 +83,7 @@ public class RankingHelper implements RankingConfig { Slog.w(TAG, "Problem accessing extractor " + extractorNames[i] + ".", e); } } mProxyByGroupTmp = new ArrayMap<String, NotificationRecord>(); } public void extractSignals(NotificationRecord r) { Loading Loading @@ -166,11 +167,39 @@ public class RankingHelper implements RankingConfig { } public void sort(ArrayList<NotificationRecord> notificationList) { Collections.sort(notificationList, mRankingComparator); final int N = notificationList.size(); // clear group proxies for (int i = N - 1; i >= 0; i--) { notificationList.get(i).setRankingProxy(null); } // rank each record individually Collections.sort(notificationList, mPreliminaryComparator); // record inidivdual ranking result and nominate proxies for each group for (int i = N - 1; i >= 0; i--) { final NotificationRecord record = notificationList.get(i); record.setAuthoritativeRank(i); final String groupKey = record.getGroupKey(); boolean isGroupSummary = record.getNotification().getGroup() != null && (record.getNotification().flags & Notification.FLAG_GROUP_SUMMARY) != 0; if (isGroupSummary || mProxyByGroupTmp.get(groupKey) == null) { mProxyByGroupTmp.put(groupKey, record); } } // assign nominated proxies to each notification for (int i = 0; i < N; i++) { final NotificationRecord record = notificationList.get(i); record.setRankingProxy(mProxyByGroupTmp.get(record.getGroupKey())); } // Do a second ranking pass, using group proxies Collections.sort(notificationList, mFinalComparator); mProxyByGroupTmp.clear(); } public int indexOf(ArrayList<NotificationRecord> notificationList, NotificationRecord target) { return Collections.binarySearch(notificationList, target, mRankingComparator); return Collections.binarySearch(notificationList, target, mFinalComparator); } private static int safeInt(XmlPullParser parser, String att, int defValue) { Loading