Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 330459d6 authored by Christoph Studer's avatar Christoph Studer Committed by Android (Google) Code Review
Browse files

Merge "NoMan: Fix inconsistent notification comparator" into lmp-dev

parents e7b6b1aa cd4adf8b
Loading
Loading
Loading
Loading
+34 −0
Original line number Original line Diff line number Diff line
@@ -15,43 +15,20 @@
 */
 */
package com.android.server.notification;
package com.android.server.notification;


import android.text.TextUtils;
import java.util.Comparator;
import android.util.Log;


/**
/**
 * Sorts notifications, accounting for groups and sort keys.
 * Sorts notifications by their global sort key.
 */
 */
public class GroupedNotificationComparator extends NotificationComparator {
public class GlobalSortKeyComparator implements Comparator<NotificationRecord> {
    private static final String TAG = "GroupedNotificationComparator";

    @Override
    @Override
    public int compare(NotificationRecord left, NotificationRecord right) {
    public int compare(NotificationRecord left, NotificationRecord right) {
        // "recently intrusive" is an ad hoc group that temporarily claims noisy notifications
        if (left.getGlobalSortKey() == null) {
        if (left.isRecentlyIntrusive() != right.isRecentlyIntrusive()) {
            throw new IllegalStateException("Missing left global sort key: " + left);
            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();
        if (right.getGlobalSortKey() == null) {
        final String rightSortKey = right.getNotification().getSortKey();
            throw new IllegalStateException("Missing right global sort key: " + right);
        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);
        }
        }
        return left.getGlobalSortKey().compareTo(right.getGlobalSortKey());
    }
    }
}
}
+44 −60
Original line number Original line Diff line number Diff line
@@ -1605,6 +1605,8 @@ public class NotificationManagerService extends SystemService {
            @Override
            @Override
            public void run() {
            public void run() {


                synchronized (mNotificationList) {

                    // === Scoring ===
                    // === Scoring ===


                    // 0. Sanitize inputs
                    // 0. Sanitize inputs
@@ -1653,7 +1655,6 @@ public class NotificationManagerService extends SystemService {
                        return;
                        return;
                    }
                    }


                synchronized (mNotificationList) {
                    // Clear out group children of the old notification if the update causes the
                    // Clear out group children of the old notification if the update causes the
                    // group summary to go away. This happens when the old notification was a
                    // group summary to go away. This happens when the old notification was a
                    // summary and the new one isn't, or when the old notification was a summary
                    // summary and the new one isn't, or when the old notification was a summary
@@ -1688,24 +1689,7 @@ public class NotificationManagerService extends SystemService {
                    }
                    }


                    applyZenModeLocked(r);
                    applyZenModeLocked(r);

                    try {
                    mRankingHelper.sort(mNotificationList);
                    mRankingHelper.sort(mNotificationList);
                    } catch (RuntimeException ex) {
                        // Don't crash the system server if something bad happened.
                        Log.e(TAG, "Extreme badness during notification sort", ex);
                        Log.e(TAG, "Current notification list: ");
                        for (int ii=0; ii < mNotificationList.size(); ii++) {
                            NotificationRecord nr = mNotificationList.get(ii);
                            Log.e(TAG, String.format(
                                    "  [%d] %s (group %s, rank %d, sortkey %s, proxy %s)",
                                    ii, nr, nr.getGroupKey(), nr.getAuthoritativeRank(),
                                    nr.getNotification().getSortKey(),
                                    nr.getRankingProxy()));
                        }
                        // STOPSHIP: remove once b/16626175 is found
                        throw ex;
                    }


                    if (notification.icon != 0) {
                    if (notification.icon != 0) {
                        StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
                        StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
+7 −9
Original line number Original line Diff line number Diff line
@@ -63,9 +63,8 @@ public final class NotificationRecord {
    public boolean isUpdate;
    public boolean isUpdate;
    private int mPackagePriority;
    private int mPackagePriority;


    // The record that ranking should use for comparisons outside the group.
    private NotificationRecord mRankingProxy;
    private int mAuthoritativeRank;
    private int mAuthoritativeRank;
    private String mGlobalSortKey;


    @VisibleForTesting
    @VisibleForTesting
    public NotificationRecord(StatusBarNotification sbn, int score)
    public NotificationRecord(StatusBarNotification sbn, int score)
@@ -81,9 +80,8 @@ public final class NotificationRecord {
        mRecentlyIntrusive = previous.mRecentlyIntrusive;
        mRecentlyIntrusive = previous.mRecentlyIntrusive;
        mPackagePriority = previous.mPackagePriority;
        mPackagePriority = previous.mPackagePriority;
        mIntercept = previous.mIntercept;
        mIntercept = previous.mIntercept;
        mRankingProxy = previous.mRankingProxy;
        mRankingTimeMs = calculateRankingTimeMs(previous.getRankingTimeMs());
        mRankingTimeMs = calculateRankingTimeMs(previous.getRankingTimeMs());
        // Don't copy mGroupKey, recompute it, in case it has changed
        // Don't copy mGlobalSortKey, recompute it.
    }
    }


    public Notification getNotification() { return sbn.getNotification(); }
    public Notification getNotification() { return sbn.getNotification(); }
@@ -158,7 +156,7 @@ public final class NotificationRecord {
        pw.println(prefix + "  mRecentlyIntrusive=" + mRecentlyIntrusive);
        pw.println(prefix + "  mRecentlyIntrusive=" + mRecentlyIntrusive);
        pw.println(prefix + "  mPackagePriority=" + mPackagePriority);
        pw.println(prefix + "  mPackagePriority=" + mPackagePriority);
        pw.println(prefix + "  mIntercept=" + mIntercept);
        pw.println(prefix + "  mIntercept=" + mIntercept);
        pw.println(prefix + "  mRankingProxy=" + getRankingProxy().getKey());
        pw.println(prefix + "  mGlobalSortKey=" + mGlobalSortKey);
        pw.println(prefix + "  mRankingTimeMs=" + mRankingTimeMs);
        pw.println(prefix + "  mRankingTimeMs=" + mRankingTimeMs);
    }
    }


@@ -265,12 +263,12 @@ public final class NotificationRecord {
        return sbn.getPostTime();
        return sbn.getPostTime();
    }
    }


    public NotificationRecord getRankingProxy() {
    public void setGlobalSortKey(String globalSortKey) {
        return mRankingProxy;
        mGlobalSortKey = globalSortKey;
    }
    }


    public void setRankingProxy(NotificationRecord proxy) {
    public String getGlobalSortKey() {
        mRankingProxy = proxy;
        return mGlobalSortKey;
    }
    }


    public void setAuthoritativeRank(int authoritativeRank) {
    public void setAuthoritativeRank(int authoritativeRank) {
+64 −22
Original line number Original line Diff line number Diff line
@@ -17,12 +17,12 @@ package com.android.server.notification;


import android.app.Notification;
import android.app.Notification;
import android.content.Context;
import android.content.Context;
import android.net.Uri;
import android.os.Handler;
import android.os.Handler;
import android.os.Message;
import android.os.Message;
import android.os.UserHandle;
import android.os.UserHandle;
import android.text.TextUtils;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
import android.util.Slog;
import android.util.SparseIntArray;
import android.util.SparseIntArray;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParser;
@@ -33,6 +33,7 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Collections;
import java.util.Comparator;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeUnit;


public class RankingHelper implements RankingConfig {
public class RankingHelper implements RankingConfig {
@@ -51,7 +52,7 @@ public class RankingHelper implements RankingConfig {


    private final NotificationSignalExtractor[] mSignalExtractors;
    private final NotificationSignalExtractor[] mSignalExtractors;
    private final NotificationComparator mPreliminaryComparator = new NotificationComparator();
    private final NotificationComparator mPreliminaryComparator = new NotificationComparator();
    private final NotificationComparator mFinalComparator = new GroupedNotificationComparator();
    private final GlobalSortKeyComparator mFinalComparator = new GlobalSortKeyComparator();


    // Package name to uid, to priority. Would be better as Table<String, Int, Int>
    // Package name to uid, to priority. Would be better as Table<String, Int, Int>
    private final ArrayMap<String, SparseIntArray> mPackagePriorities;
    private final ArrayMap<String, SparseIntArray> mPackagePriorities;
@@ -168,36 +169,77 @@ public class RankingHelper implements RankingConfig {


    public void sort(ArrayList<NotificationRecord> notificationList) {
    public void sort(ArrayList<NotificationRecord> notificationList) {
        final int N = notificationList.size();
        final int N = notificationList.size();
        // clear group proxies
        // clear global sort keys
        for (int i = N - 1; i >= 0; i--) {
        for (int i = N - 1; i >= 0; i--) {
            notificationList.get(i).setRankingProxy(null);
            notificationList.get(i).setGlobalSortKey(null);
        }
        }


        try {
            // rank each record individually
            // rank each record individually
            Collections.sort(notificationList, mPreliminaryComparator);
            Collections.sort(notificationList, mPreliminaryComparator);
        } catch (RuntimeException ex) {
            // Don't crash the system server if something bad happened.
            Log.e(TAG, "Extreme badness during notification sort", ex);
            Log.e(TAG, "Current notification list: ");
            for (int i = 0; i < N; i++) {
                NotificationRecord nr = notificationList.get(i);
                Log.e(TAG, String.format(
                        "  [%d] %s (group %s, rank %d, sortkey %s)",
                        i, nr, nr.getGroupKey(), nr.getAuthoritativeRank(),
                        nr.getNotification().getSortKey()));
            }
            // STOPSHIP: remove once b/16626175 is found
            throw ex;
        }


        // record inidivdual ranking result and nominate proxies for each group
        synchronized (mProxyByGroupTmp) {
            // record individual ranking result and nominate proxies for each group
            for (int i = N - 1; i >= 0; i--) {
            for (int i = N - 1; i >= 0; i--) {
                final NotificationRecord record = notificationList.get(i);
                final NotificationRecord record = notificationList.get(i);
                record.setAuthoritativeRank(i);
                record.setAuthoritativeRank(i);
                final String groupKey = record.getGroupKey();
                final String groupKey = record.getGroupKey();
            boolean isGroupSummary = record.getNotification().getGroup() != null
                boolean isGroupSummary = record.getNotification().isGroupSummary();
                    && (record.getNotification().flags & Notification.FLAG_GROUP_SUMMARY) != 0;
                if (isGroupSummary || !mProxyByGroupTmp.containsKey(groupKey)) {
            if (isGroupSummary || mProxyByGroupTmp.get(groupKey) == null) {
                    mProxyByGroupTmp.put(groupKey, record);
                    mProxyByGroupTmp.put(groupKey, record);
                }
                }
            }
            }
        // assign nominated proxies to each notification
            // assign global sort key:
            //   is_recently_intrusive:group_rank:is_group_summary:group_sort_key:rank
            for (int i = 0; i < N; i++) {
            for (int i = 0; i < N; i++) {
                final NotificationRecord record = notificationList.get(i);
                final NotificationRecord record = notificationList.get(i);
            record.setRankingProxy(mProxyByGroupTmp.get(record.getGroupKey()));
                NotificationRecord groupProxy = mProxyByGroupTmp.get(record.getGroupKey());
                String groupSortKey = record.getNotification().getSortKey();

                // We need to make sure the developer provided group sort key (gsk) is handled
                // correctly:
                //   gsk="" < gsk=non-null-string < gsk=null
                //
                // We enforce this by using different prefixes for these three cases.
                String groupSortKeyPortion;
                if (groupSortKey == null) {
                    groupSortKeyPortion = "nsk";
                } else if (groupSortKey.equals("")) {
                    groupSortKeyPortion = "esk";
                } else {
                    groupSortKeyPortion = "gsk=" + groupSortKey;
                }
                }
        // Do a second ranking pass, using group proxies
        Collections.sort(notificationList, mFinalComparator);


                boolean isGroupSummary = record.getNotification().isGroupSummary();
                record.setGlobalSortKey(
                        String.format("intrsv=%c:grnk=0x%04x:gsmry=%c:%s:rnk=0x%04x",
                        record.isRecentlyIntrusive() ? '0' : '1',
                        groupProxy.getAuthoritativeRank(),
                        isGroupSummary ? '0' : '1',
                        groupSortKeyPortion,
                        record.getAuthoritativeRank()));
            }
            mProxyByGroupTmp.clear();
            mProxyByGroupTmp.clear();
        }
        }


        // Do a second ranking pass, using group proxies
        Collections.sort(notificationList, mFinalComparator);
    }

    public int indexOf(ArrayList<NotificationRecord> notificationList, NotificationRecord target) {
    public int indexOf(ArrayList<NotificationRecord> notificationList, NotificationRecord target) {
        return Collections.binarySearch(notificationList, target, mFinalComparator);
        return Collections.binarySearch(notificationList, target, mFinalComparator);
    }
    }