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

Commit c3e4054c authored by Danny Baumann's avatar Danny Baumann Committed by Steve Kondik
Browse files

Support enforcing a minimum delay between notification sounds of an app.

Useful e.g. for messenger apps.

Change-Id: If8e8cc9e2f02d70537c1f9dc14f22bbd0ec1e9a6
parent 62262024
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -56,6 +56,8 @@ interface INotificationManager
    void setImportance(String pkg, int uid, int importance);
    int getImportance(String pkg, int uid);
    int getPackageImportance(String pkg);
    void setNotificationSoundTimeout(String pkg, int uid, long timeout);
    long getNotificationSoundTimeout(String pkg, int uid);

    // TODO: Remove this when callers have been migrated to the equivalent
    // INotificationListener method.
+47 −0
Original line number Diff line number Diff line
@@ -125,6 +125,7 @@ import android.util.AtomicFile;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
import android.util.Xml;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -303,6 +304,7 @@ public class NotificationManagerService extends SystemService {
    final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
    final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
    final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
    final ArrayMap<String, Long> mLastSoundTimestamps = new ArrayMap<>();
    final PolicyAccess mPolicyAccess = new PolicyAccess();

    // The last key in this list owns the hardware.
@@ -1632,6 +1634,19 @@ public class NotificationManagerService extends SystemService {
            return mRankingHelper.getImportance(pkg, uid);
        }

        @Override
        public void setNotificationSoundTimeout(String pkg, int uid, long timeout) {
            checkCallerIsSystem();
            mRankingHelper.setNotificationSoundTimeout(pkg, uid, timeout);
            savePolicyFile();
        }

        @Override
        public long getNotificationSoundTimeout(String pkg, int uid) {
            checkCallerIsSystem();
            return mRankingHelper.getNotificationSoundTimeout(pkg, uid);
        }

        /**
         * System-only API for getting a list of current (i.e. not cleared) notifications.
         *
@@ -2625,6 +2640,14 @@ public class NotificationManagerService extends SystemService {
                    r.dump(pw, "      ", getContext(), filter.redact);
                }
            }

            long now = SystemClock.elapsedRealtime();
            pw.println("\n  Last notification sound timestamps:");
            for (Map.Entry<String, Long> entry: mLastSoundTimestamps.entrySet()) {
                pw.print("    " + entry.getKey() + " -> ");
                TimeUtils.formatDuration(entry.getValue(), now, pw);
                pw.println(" ago");
            }
        }
    }

@@ -2981,6 +3004,7 @@ public class NotificationManagerService extends SystemService {
                && (record.getUserId() == UserHandle.USER_ALL ||
                    record.getUserId() == currentUser ||
                    mUserProfiles.isCurrentProfile(record.getUserId()))
                && !isInSoundTimeoutPeriod(record)
                && mSystemReady
                && mAudioManager != null;

@@ -3121,6 +3145,11 @@ public class NotificationManagerService extends SystemService {
        } else if (wasShowLights) {
            updateLightsLocked();
        }

        if (buzz || beep) {
            mLastSoundTimestamps.put(generateLastSoundTimeoutKey(record),
                    SystemClock.elapsedRealtime());
        }
        if (buzz || beep || blink) {
            if (((record.getSuppressedVisualEffects()
                    & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) != 0)) {
@@ -3133,6 +3162,24 @@ public class NotificationManagerService extends SystemService {
        }
    }

    private boolean isInSoundTimeoutPeriod(NotificationRecord record) {
        long timeoutMillis = mRankingHelper.getNotificationSoundTimeout(
                record.sbn.getPackageName(), record.sbn.getUid());
        if (timeoutMillis == 0) {
            return false;
        }

        Long value = mLastSoundTimestamps.get(generateLastSoundTimeoutKey(record));
        if (value == null) {
            return false;
        }
        return SystemClock.elapsedRealtime() - value < timeoutMillis;
    }

    private String generateLastSoundTimeoutKey(NotificationRecord record) {
        return record.sbn.getPackageName() + "|" + record.sbn.getUid();
    }

    private static AudioAttributes audioAttributesForNotification(Notification n) {
        if (n.audioAttributes != null
                && !Notification.AUDIO_ATTRIBUTES_DEFAULT.equals(n.audioAttributes)) {
+26 −1
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ public class RankingHelper implements RankingConfig {
    private static final String ATT_IMPORTANCE = "importance";
    private static final String ATT_TOPIC_ID = "id";
    private static final String ATT_TOPIC_LABEL = "label";
    private static final String ATT_SOUND_TIMEOUT = "sound-timeout";

    private static final int DEFAULT_PRIORITY = Notification.PRIORITY_DEFAULT;
    private static final int DEFAULT_VISIBILITY = Ranking.VISIBILITY_NO_OVERRIDE;
@@ -166,6 +167,7 @@ public class RankingHelper implements RankingConfig {
                        r.importance = safeInt(parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
                        r.priority = safeInt(parser, ATT_PRIORITY, DEFAULT_PRIORITY);
                        r.visibility = safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY);
                        r.soundTimeout = safeInt(parser, ATT_SOUND_TIMEOUT, 0);
                    }
                }
            }
@@ -201,7 +203,9 @@ public class RankingHelper implements RankingConfig {
                continue;
            }
            final boolean hasNonDefaultSettings = r.importance != DEFAULT_IMPORTANCE
                    || r.priority != DEFAULT_PRIORITY || r.visibility != DEFAULT_VISIBILITY;
                    || r.priority != DEFAULT_PRIORITY
                    || r.visibility != DEFAULT_VISIBILITY
                    || r.soundTimeout != 0;
            if (hasNonDefaultSettings) {
                out.startTag(null, TAG_PACKAGE);
                out.attribute(null, ATT_NAME, r.pkg);
@@ -214,6 +218,9 @@ public class RankingHelper implements RankingConfig {
                if (r.visibility != DEFAULT_VISIBILITY) {
                    out.attribute(null, ATT_VISIBILITY, Integer.toString(r.visibility));
                }
                if (r.soundTimeout != 0) {
                    out.attribute(null, ATT_SOUND_TIMEOUT, Long.toString(r.soundTimeout));
                }

                if (!forBackup) {
                    out.attribute(null, ATT_UID, Integer.toString(r.uid));
@@ -373,6 +380,15 @@ public class RankingHelper implements RankingConfig {
        setImportance(packageName, uid, enabled ? DEFAULT_IMPORTANCE : Ranking.IMPORTANCE_NONE);
    }

    public long getNotificationSoundTimeout(String packageName, int uid) {
        return getOrCreateRecord(packageName, uid).soundTimeout;
    }

    public void setNotificationSoundTimeout(String packageName, int uid, long timeout) {
        getOrCreateRecord(packageName, uid).soundTimeout = timeout;
        updateConfig();
    }

    public void dump(PrintWriter pw, String prefix, NotificationManagerService.DumpFilter filter) {
        if (filter == null) {
            final int N = mSignalExtractors.length;
@@ -419,6 +435,11 @@ public class RankingHelper implements RankingConfig {
                    pw.print(" visibility=");
                    pw.print(Notification.visibilityToString(r.visibility));
                }
                if (r.soundTimeout != 0) {
                    pw.print(" soundTimeout=");
                    pw.print(r.soundTimeout);
                    pw.print("ms");
                }
                pw.println();
            }
        }
@@ -449,6 +470,9 @@ public class RankingHelper implements RankingConfig {
                    if (r.visibility != DEFAULT_VISIBILITY) {
                        record.put("visibility", Notification.visibilityToString(r.visibility));
                    }
                    if (r.soundTimeout != 0) {
                        record.put("soundTimeout", r.soundTimeout);
                    }
                } catch (JSONException e) {
                   // pass
                }
@@ -538,5 +562,6 @@ public class RankingHelper implements RankingConfig {
        int importance = DEFAULT_IMPORTANCE;
        int priority = DEFAULT_PRIORITY;
        int visibility = DEFAULT_VISIBILITY;
        long soundTimeout = 0;
   }
}