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

Commit a344656a authored by Chris Wren's avatar Chris Wren
Browse files

A notification that emerges from Zen Mode interception should beep.

If a notificaiton emerges from Zen Mode due to a ranking
reconsideration (possibly because a long-running query resolved an
important person) then it should get the oportunity buzz, beep, blink,
and send accessibility events.

Save what we need to know about the old notificaiton record on the new
record so we don't have to hold onto it.

Bug: 15383458
Change-Id: I15c7834fef03ff6a676e78e9d2caae24f00720ef
parent 7256a852
Loading
Loading
Loading
Loading
+169 −159
Original line number Diff line number Diff line
@@ -182,7 +182,7 @@ public class NotificationManagerService extends SystemService {
            new ArrayMap<String, NotificationRecord>();
    final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();

    ArrayList<NotificationRecord> mLights = new ArrayList<NotificationRecord>();
    ArrayList<String> mLights = new ArrayList<String>();
    NotificationRecord mLedNotification;

    private AppOpsManager mAppOps;
@@ -1478,14 +1478,14 @@ public class NotificationManagerService extends SystemService {
                    }
                }

                // 1. initial score: buckets of 10, around the app
                int score = notification.priority * NOTIFICATION_PRIORITY_MULTIPLIER; //[-20..20]
                // 1. initial score: buckets of 10, around the app [-20..20]
                final int score = notification.priority * NOTIFICATION_PRIORITY_MULTIPLIER;

                // 2. extract ranking signals from the notification data
                final StatusBarNotification n = new StatusBarNotification(
                        pkg, opPkg, id, tag, callingUid, callingPid, score, notification,
                        user);
                NotificationRecord r = new NotificationRecord(n);
                NotificationRecord r = new NotificationRecord(n, score);
                NotificationRecord old = mNotificationsByKey.get(n.getKey());
                if (old != null) {
                    // Retain ranking information from previous record
@@ -1507,13 +1507,13 @@ public class NotificationManagerService extends SystemService {
                // blocked apps
                if (ENABLE_BLOCKED_NOTIFICATIONS && !noteNotificationOp(pkg, callingUid)) {
                    if (!isSystemNotification) {
                        score = JUNK_SCORE;
                        r.score = JUNK_SCORE;
                        Slog.e(TAG, "Suppressing notification from package " + pkg
                                + " by user request.");
                    }
                }

                if (score < SCORE_DISPLAY_THRESHOLD) {
                if (r.score < SCORE_DISPLAY_THRESHOLD) {
                    // Notification will be blocked because the score is too low.
                    return;
                }
@@ -1531,26 +1531,14 @@ public class NotificationManagerService extends SystemService {
                        notification.flags |=
                                old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
                        mNotificationsByKey.remove(old.sbn.getKey());
                        r.isUpdate = true;
                    }
                    mNotificationsByKey.put(n.getKey(), r);

                    applyZenModeLocked(r);
                    // Should this notification make noise, vibe, or use the LED?
                    final boolean canInterrupt = (score >= SCORE_INTERRUPTION_THRESHOLD) &&
                            !r.isIntercepted();
                    if (DBG || r.isIntercepted()) Slog.v(TAG,
                            "pkg=" + pkg + " canInterrupt=" + canInterrupt +
                                    " intercept=" + r.isIntercepted());

                    Collections.sort(mNotificationList, mRankingComparator);

                    // Ensure if this is a foreground service that the proper additional
                    // flags are set.
                    if ((notification.flags&Notification.FLAG_FOREGROUND_SERVICE) != 0) {
                        notification.flags |= Notification.FLAG_ONGOING_EVENT
                                | Notification.FLAG_NO_CLEAR;
                    }

                    final int currentUser;
                    final long token = Binder.clearCallingIdentity();
                    try {
@@ -1571,20 +1559,11 @@ public class NotificationManagerService extends SystemService {
                            final long identity = Binder.clearCallingIdentity();
                            try {
                                mStatusBar.addNotification(n);
                                if ((n.getNotification().flags & Notification.FLAG_SHOW_LIGHTS) != 0
                                        && canInterrupt) {
                                    mAttentionLight.pulse();
                                }
                            } finally {
                                Binder.restoreCallingIdentity(identity);
                            }
                        }
                        // Send accessibility events only for the current user.
                        if (currentUser == userId) {
                            sendAccessibilityEvent(notification, pkg);
                        }

                        mListeners.notifyPostedLocked(r.sbn);
                        mListeners.notifyPostedLocked(n);
                    } else {
                        Slog.e(TAG, "Not posting notification with icon==0: " + notification);
                        if (old != null && !old.isCanceled) {
@@ -1595,7 +1574,7 @@ public class NotificationManagerService extends SystemService {
                                Binder.restoreCallingIdentity(identity);
                            }

                            mListeners.notifyRemovedLocked(r.sbn);
                            mListeners.notifyRemovedLocked(n);
                        }
                        // ATTENTION: in a future release we will bail out here
                        // so that we do not play sounds, show lights, etc. for invalid
@@ -1604,17 +1583,55 @@ public class NotificationManagerService extends SystemService {
                                + n.getPackageName());
                    }

                    // Ensure if this is a foreground service that the proper additional
                    // flags are set.
                    if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
                        notification.flags |= Notification.FLAG_ONGOING_EVENT
                                | Notification.FLAG_NO_CLEAR;
                    }

                    buzzBeepBlinkLocked(r);
                }
            }
        });

        idOut[0] = id;
    }

    private void buzzBeepBlinkLocked(NotificationRecord record) {
        final Notification notification = record.sbn.getNotification();

        // Should this notification make noise, vibe, or use the LED?
        final boolean canInterrupt = (record.score >= SCORE_INTERRUPTION_THRESHOLD) &&
                !record.isIntercepted();
        if (DBG || record.isIntercepted())
            Slog.v(TAG,
                    "pkg=" + record.sbn.getPackageName() + " canInterrupt=" + canInterrupt +
                            " intercept=" + record.isIntercepted()
            );

        final int currentUser;
        final long token = Binder.clearCallingIdentity();
        try {
            currentUser = ActivityManager.getCurrentUser();
        } finally {
            Binder.restoreCallingIdentity(token);
        }

        // If we're not supposed to beep, vibrate, etc. then don't.
        if (!mDisableNotificationAlerts
                            && (!(old != null
                && (!(record.isUpdate
                    && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
                            && (r.getUserId() == UserHandle.USER_ALL ||
                                (r.getUserId() == userId && r.getUserId() == currentUser) ||
                                mUserProfiles.isCurrentProfile(r.getUserId()))
                && (record.getUserId() == UserHandle.USER_ALL ||
                    record.getUserId() == currentUser ||
                    mUserProfiles.isCurrentProfile(record.getUserId()))
                && canInterrupt
                && mSystemReady
                && mAudioManager != null) {
            if (DBG) Slog.v(TAG, "Interrupting!");

            sendAccessibilityEvent(notification, record.sbn.getPackageName());

            // sound

            // should we use the default notification sound? (indicated either by
@@ -1649,7 +1666,7 @@ public class NotificationManagerService extends SystemService {
                } else {
                    audioStreamType = DEFAULT_STREAM_TYPE;
                }
                            mSoundNotification = r;
                mSoundNotification = record;
                // do not play notifications if stream volume is 0 (typically because
                // ringer mode is silent) or if there is a user of exclusive audio focus
                if ((mAudioManager.getStreamVolume(audioStreamType) != 0)
@@ -1661,7 +1678,8 @@ public class NotificationManagerService extends SystemService {
                        if (player != null) {
                            if (DBG) Slog.v(TAG, "Playing sound " + soundUri
                                    + " on stream " + audioStreamType);
                                        player.playAsync(soundUri, user, looping, audioStreamType);
                            player.playAsync(soundUri, record.sbn.getUser(), looping,
                                    audioStreamType);
                        }
                    } catch (RemoteException e) {
                    } finally {
@@ -1689,14 +1707,14 @@ public class NotificationManagerService extends SystemService {
            if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate)
                    && !(mAudioManager.getRingerMode()
                            == AudioManager.RINGER_MODE_SILENT)) {
                            mVibrateNotification = r;
                mVibrateNotification = record;

                if (useDefaultVibrate || convertSoundToVibration) {
                    // Escalate privileges so we can use the vibrator even if the
                    // notifying app does not have the VIBRATE permission.
                    long identity = Binder.clearCallingIdentity();
                    try {
                                    mVibrator.vibrate(r.sbn.getUid(), r.sbn.getOpPkg(),
                        mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
                            useDefaultVibrate ? mDefaultVibrationPattern
                                : mFallbackVibrationPattern,
                            ((notification.flags & Notification.FLAG_INSISTENT) != 0)
@@ -1707,7 +1725,7 @@ public class NotificationManagerService extends SystemService {
                } else if (notification.vibrate.length > 1) {
                    // If you want your own vibration pattern, you need the VIBRATE
                    // permission
                                mVibrator.vibrate(r.sbn.getUid(), r.sbn.getOpPkg(),
                    mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
                            notification.vibrate,
                        ((notification.flags & Notification.FLAG_INSISTENT) != 0)
                                ? 0: -1, notification.audioStreamType);
@@ -1716,30 +1734,19 @@ public class NotificationManagerService extends SystemService {
        }

        // light
                    // the most recent thing gets the light
                    mLights.remove(old);
                    if (mLedNotification == old) {
        // release the light
        boolean wasShowLights = mLights.remove(record.getKey());
        if (mLedNotification != null && record.getKey().equals(mLedNotification.getKey())) {
            mLedNotification = null;
        }
                    //Slog.i(TAG, "notification.lights="
                    //        + ((old.notification.lights.flags & Notification.FLAG_SHOW_LIGHTS)
                    //                  != 0));
                    if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0
                            && canInterrupt) {
                        mLights.add(r);
        if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && canInterrupt) {
            mLights.add(record.getKey());
            updateLightsLocked();
                    } else {
                        if (old != null
                                && ((old.getFlags() & Notification.FLAG_SHOW_LIGHTS) != 0)) {
            mAttentionLight.pulse();
        } else if (wasShowLights) {
            updateLightsLocked();
        }
    }
                }
            }
        });

        idOut[0] = id;
    }

    void showNextToastLocked() {
        ToastRecord record = mToastQueue.get(0);
@@ -1866,6 +1873,9 @@ public class NotificationManagerService extends SystemService {
            int indexAfter = findNotificationRecordIndexLocked(record);
            boolean interceptAfter = record.isIntercepted();
            changed = indexBefore != indexAfter || interceptBefore != interceptAfter;
            if (interceptBefore && !interceptAfter) {
                buzzBeepBlinkLocked(record);
            }
        }
        if (changed) {
            scheduleSendRankingUpdate();
@@ -2011,7 +2021,7 @@ public class NotificationManagerService extends SystemService {
        }

        // light
        mLights.remove(r);
        mLights.remove(r.getKey());
        if (mLedNotification == r) {
            mLedNotification = null;
        }
@@ -2196,7 +2206,7 @@ public class NotificationManagerService extends SystemService {
            // get next notification, if any
            int n = mLights.size();
            if (n > 0) {
                mLedNotification = mLights.get(n-1);
                mLedNotification = mNotificationsByKey.get(mLights.get(n-1));
            }
        }

+6 −1
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ public final class NotificationRecord {
    final StatusBarNotification sbn;
    NotificationUsageStats.SingleNotificationStats stats;
    boolean isCanceled;
    int score;

    // These members are used by NotificationSignalExtractors
    // to communicate with the ranking module.
@@ -53,9 +54,13 @@ public final class NotificationRecord {
    // InterceptedNotifications needs to know if this has been previously evaluated.
    private boolean mTouchedByZen;

    NotificationRecord(StatusBarNotification sbn)
    // Is this record an update of an old record?
    public boolean isUpdate;

    NotificationRecord(StatusBarNotification sbn, int score)
    {
        this.sbn = sbn;
        this.score = score;
    }

    // copy any notes that the ranking system may have made before the update