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

Commit 82b085e4 authored by Automerger Merge Worker's avatar Automerger Merge Worker
Browse files

Merge changes Ic91ff7ac,I7d118592 into rvc-dev am: b2c82a05 am: 2007a875

Change-Id: Iac94bb0d47f82c1390b6b61a82b4af5f2b7f7e17
parents 25f380d1 2007a875
Loading
Loading
Loading
Loading
+26 −17
Original line number Diff line number Diff line
@@ -2068,20 +2068,17 @@ public class NotificationManagerService extends SystemService {

    @Override
    public void onStart() {
        SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() {
            @Override
            public void repost(int userId, NotificationRecord r) {
        SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), (userId, r, muteOnReturn) -> {
            try {
                if (DBG) {
                    Slog.d(TAG, "Reposting " + r.getKey());
                }
                enqueueNotificationInternal(r.getSbn().getPackageName(), r.getSbn().getOpPkg(),
                        r.getSbn().getUid(), r.getSbn().getInitialPid(), r.getSbn().getTag(),
                            r.getSbn().getId(),  r.getSbn().getNotification(), userId);
                        r.getSbn().getId(),  r.getSbn().getNotification(), userId, true);
            } catch (Exception e) {
                Slog.e(TAG, "Cannot un-snooze notification", e);
            }
            }
        }, mUserProfiles);

        final File systemDir = new File(Environment.getDataDirectory(), "system");
@@ -3983,7 +3980,7 @@ public class NotificationManagerService extends SystemService {
                synchronized (mNotificationLock) {
                    final ManagedServiceInfo info =
                            mAssistants.checkServiceTokenLocked(token);
                    unsnoozeNotificationInt(key, info);
                    unsnoozeNotificationInt(key, info, false);
                }
            } finally {
                Binder.restoreCallingIdentity(identity);
@@ -4006,7 +4003,7 @@ public class NotificationManagerService extends SystemService {
                    if (!info.isSystem) {
                        throw new SecurityException("Not allowed to unsnooze before deadline");
                    }
                    unsnoozeNotificationInt(key, info);
                    unsnoozeNotificationInt(key, info, true);
                }
            } finally {
                Binder.restoreCallingIdentity(identity);
@@ -5525,6 +5522,13 @@ public class NotificationManagerService extends SystemService {
    void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
            final int callingPid, final String tag, final int id, final Notification notification,
            int incomingUserId) {
        enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
        incomingUserId, false);
    }

    void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
        final int callingPid, final String tag, final int id, final Notification notification,
        int incomingUserId, boolean postSilently) {
        if (DBG) {
            Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
                    + " notification=" + notification);
@@ -5605,6 +5609,7 @@ public class NotificationManagerService extends SystemService {
                user, null, System.currentTimeMillis());
        final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
        r.setIsAppImportanceLocked(mPreferencesHelper.getIsAppImportanceLocked(pkg, callingUid));
        r.setPostSilently(postSilently);

        if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
            final boolean fgServiceShown = channel.isFgServiceShown();
@@ -7040,6 +7045,11 @@ public class NotificationManagerService extends SystemService {
            return true;
        }

        // Suppressed because a user manually unsnoozed something (or similar)
        if (record.shouldPostSilently()) {
            return true;
        }

        // muted by listener
        final String disableEffects = disableNotificationEffects(record);
        if (disableEffects != null) {
@@ -8054,13 +8064,12 @@ public class NotificationManagerService extends SystemService {
        mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
    }

    void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
    void unsnoozeNotificationInt(String key, ManagedServiceInfo listener, boolean muteOnReturn) {
        String listenerName = listener == null ? null : listener.component.toShortString();
        if (DBG) {
            Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
        }
        mSnoozeHelper.cleanupPersistedContext(key);
        mSnoozeHelper.repost(key);
        mSnoozeHelper.repost(key, muteOnReturn);
        handleSavePolicyFile();
    }

+12 −0
Original line number Diff line number Diff line
@@ -187,6 +187,7 @@ public final class NotificationRecord {
    private boolean mSuggestionsGeneratedByAssistant;
    private boolean mEditChoicesBeforeSending;
    private boolean mHasSeenSmartReplies;
    private boolean mPostSilently;
    /**
     * Whether this notification (and its channels) should be considered user locked. Used in
     * conjunction with user sentiment calculation.
@@ -856,6 +857,17 @@ public final class NotificationRecord {
        return mHidden;
    }

    /**
     * Override of all alerting information on the channel and notification. Used when notifications
     * are reposted in response to direct user action and thus don't need to alert.
     */
    public void setPostSilently(boolean postSilently) {
        mPostSilently = postSilently;
    }

    public boolean shouldPostSilently() {
        return mPostSilently;
    }

    public void setSuppressedVisualEffects(int effects) {
        mSuppressedVisualEffects = effects;
+298 −238
Original line number Diff line number Diff line
@@ -106,6 +106,8 @@ public class SnoozeHelper {
    private ArrayMap<String, Integer> mUsers = new ArrayMap<>();
    private Callback mCallback;

    private final Object mLock = new Object();

    public SnoozeHelper(Context context, Callback callback,
            ManagedServices.UserProfiles userProfiles) {
        mContext = context;
@@ -122,42 +124,53 @@ public class SnoozeHelper {
    }

    void cleanupPersistedContext(String key){
        synchronized (mLock) {
            int userId = mUsers.get(key);
            String pkg = mPackages.get(key);
        synchronized (mPersistedSnoozedNotificationsWithContext) {
            removeRecord(pkg, key, userId, mPersistedSnoozedNotificationsWithContext);
            removeRecordLocked(pkg, key, userId, mPersistedSnoozedNotificationsWithContext);
        }
    }

    //This function has a side effect of removing the time from the list of persisted notifications.
    //IT IS NOT IDEMPOTENT!
    @NonNull
    protected Long getSnoozeTimeForUnpostedNotification(int userId, String pkg, String key) {
        Long time;
        synchronized (mPersistedSnoozedNotifications) {
            time = removeRecord(pkg, key, userId, mPersistedSnoozedNotifications);
        Long time = null;
        synchronized (mLock) {
           ArrayMap<String, Long> snoozed =
                   mPersistedSnoozedNotifications.get(getPkgKey(userId, pkg));
           if (snoozed != null) {
               time = snoozed.get(key);
           }
        }
        if (time == null) {
            return 0L;
            time = 0L;
        }
        return time;
    }

    protected String getSnoozeContextForUnpostedNotification(int userId, String pkg, String key) {
        synchronized (mPersistedSnoozedNotificationsWithContext) {
            return removeRecord(pkg, key, userId, mPersistedSnoozedNotificationsWithContext);
        synchronized (mLock) {
            ArrayMap<String, String> snoozed =
                    mPersistedSnoozedNotificationsWithContext.get(getPkgKey(userId, pkg));
            if (snoozed != null) {
                return snoozed.get(key);
            }
        }
        return null;
    }

    protected boolean isSnoozed(int userId, String pkg, String key) {
        synchronized (mLock) {
            return mSnoozedNotifications.containsKey(getPkgKey(userId, pkg))
                    && mSnoozedNotifications.get(getPkgKey(userId, pkg)).containsKey(key);
        }
    }

    protected Collection<NotificationRecord> getSnoozed(int userId, String pkg) {
        synchronized (mLock) {
            if (mSnoozedNotifications.containsKey(getPkgKey(userId, pkg))) {
                return mSnoozedNotifications.get(getPkgKey(userId, pkg)).values();
            }
        }
        return Collections.EMPTY_LIST;
    }

@@ -165,6 +178,7 @@ public class SnoozeHelper {
    ArrayList<NotificationRecord> getNotifications(String pkg,
            String groupKey, Integer userId) {
        ArrayList<NotificationRecord> records =  new ArrayList<>();
        synchronized (mLock) {
            ArrayMap<String, NotificationRecord> allRecords =
                    mSnoozedNotifications.get(getPkgKey(userId, pkg));
            if (allRecords != null) {
@@ -176,10 +190,12 @@ public class SnoozeHelper {
                    }
                }
            }
        }
        return records;
    }

    protected NotificationRecord getNotification(String key) {
        synchronized (mLock) {
            if (!mUsers.containsKey(key) || !mPackages.containsKey(key)) {
                Slog.w(TAG, "Snoozed data sets no longer agree for " + key);
                return null;
@@ -193,8 +209,10 @@ public class SnoozeHelper {
            }
            return snoozed.get(key);
        }
    }

    protected @NonNull List<NotificationRecord> getSnoozed() {
        synchronized (mLock) {
            // caller filters records based on the current user profiles and listener access, so just
            // return everything
            List<NotificationRecord> snoozed = new ArrayList<>();
@@ -205,6 +223,7 @@ public class SnoozeHelper {
            }
            return snoozed;
        }
    }

    /**
     * Snoozes a notification and schedules an alarm to repost at that time.
@@ -216,9 +235,9 @@ public class SnoozeHelper {

        snooze(record);
        scheduleRepost(pkg, key, userId, duration);
        Long activateAt = SystemClock.elapsedRealtime() + duration;
        synchronized (mPersistedSnoozedNotifications) {
            storeRecord(pkg, key, userId, mPersistedSnoozedNotifications, activateAt);
        Long activateAt = System.currentTimeMillis() + duration;
        synchronized (mLock) {
            storeRecordLocked(pkg, key, userId, mPersistedSnoozedNotifications, activateAt);
        }
    }

@@ -228,8 +247,8 @@ public class SnoozeHelper {
    protected void snooze(NotificationRecord record, String contextId) {
        int userId = record.getUser().getIdentifier();
        if (contextId != null) {
            synchronized (mPersistedSnoozedNotificationsWithContext) {
                storeRecord(record.getSbn().getPackageName(), record.getKey(),
            synchronized (mLock) {
                storeRecordLocked(record.getSbn().getPackageName(), record.getKey(),
                        userId, mPersistedSnoozedNotificationsWithContext, contextId);
            }
        }
@@ -241,25 +260,26 @@ public class SnoozeHelper {
        if (DEBUG) {
            Slog.d(TAG, "Snoozing " + record.getKey());
        }
        storeRecord(record.getSbn().getPackageName(), record.getKey(),
        synchronized (mLock) {
            storeRecordLocked(record.getSbn().getPackageName(), record.getKey(),
                    userId, mSnoozedNotifications, record);
        }
    }

    private <T> void storeRecord(String pkg, String key, Integer userId,
    private <T> void storeRecordLocked(String pkg, String key, Integer userId,
            ArrayMap<String, ArrayMap<String, T>> targets, T object) {

        mPackages.put(key, pkg);
        mUsers.put(key, userId);
        ArrayMap<String, T> keyToValue = targets.get(getPkgKey(userId, pkg));
        if (keyToValue == null) {
            keyToValue = new ArrayMap<>();
        }
        keyToValue.put(key, object);
        targets.put(getPkgKey(userId, pkg), keyToValue);

        mPackages.put(key, pkg);
        mUsers.put(key, userId);
    }

    private <T> T removeRecord(String pkg, String key, Integer userId,
    private <T> T removeRecordLocked(String pkg, String key, Integer userId,
            ArrayMap<String, ArrayMap<String, T>> targets) {
        T object = null;
        ArrayMap<String, T> keyToValue = targets.get(getPkgKey(userId, pkg));
@@ -274,6 +294,7 @@ public class SnoozeHelper {
    }

    protected boolean cancel(int userId, String pkg, String tag, int id) {
        synchronized (mLock) {
            ArrayMap<String, NotificationRecord> recordsForPkg =
                    mSnoozedNotifications.get(getPkgKey(userId, pkg));
            if (recordsForPkg != null) {
@@ -286,10 +307,12 @@ public class SnoozeHelper {
                    }
                }
            }
        }
        return false;
    }

    protected void cancel(int userId, boolean includeCurrentProfiles) {
        synchronized (mLock) {
            if (mSnoozedNotifications.size() == 0) {
                return;
            }
@@ -306,8 +329,10 @@ public class SnoozeHelper {
                }
            }
        }
    }

    protected boolean cancel(int userId, String pkg) {
        synchronized (mLock) {
            ArrayMap<String, NotificationRecord> records =
                    mSnoozedNotifications.get(getPkgKey(userId, pkg));
            if (records == null) {
@@ -319,11 +344,13 @@ public class SnoozeHelper {
            }
            return true;
        }
    }

    /**
     * Updates the notification record so the most up to date information is shown on re-post.
     */
    protected void update(int userId, NotificationRecord record) {
        synchronized (mLock) {
            ArrayMap<String, NotificationRecord> records =
                    mSnoozedNotifications.get(getPkgKey(userId, record.getSbn().getPackageName()));
            if (records == null) {
@@ -331,36 +358,46 @@ public class SnoozeHelper {
            }
            records.put(record.getKey(), record);
        }
    }

    protected void repost(String key) {
    protected void repost(String key, boolean muteOnReturn) {
        synchronized (mLock) {
            Integer userId = mUsers.get(key);
            if (userId != null) {
            repost(key, userId);
                repost(key, userId, muteOnReturn);
            }
        }
    }

    protected void repost(String key, int userId) {
    protected void repost(String key, int userId, boolean muteOnReturn) {
        NotificationRecord record;
        synchronized (mLock) {
            final String pkg = mPackages.remove(key);
            mUsers.remove(key);
            removeRecordLocked(pkg, key, userId, mPersistedSnoozedNotifications);
            removeRecordLocked(pkg, key, userId, mPersistedSnoozedNotificationsWithContext);
            ArrayMap<String, NotificationRecord> records =
                    mSnoozedNotifications.get(getPkgKey(userId, pkg));
            if (records == null) {
                return;
            }
        final NotificationRecord record = records.remove(key);
        mPackages.remove(key);
        mUsers.remove(key);
            record = records.remove(key);

        }

        if (record != null && !record.isCanceled) {
            final PendingIntent pi = createPendingIntent(pkg, record.getKey(), userId);
            final PendingIntent pi = createPendingIntent(
                    record.getSbn().getPackageName(), record.getKey(), userId);
            mAm.cancel(pi);
            MetricsLogger.action(record.getLogMaker()
                    .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED)
                    .setType(MetricsProto.MetricsEvent.TYPE_OPEN));
            mCallback.repost(userId, record);
            mCallback.repost(userId, record, muteOnReturn);
        }
    }

    protected void repostGroupSummary(String pkg, int userId, String groupKey) {
        synchronized (mLock) {
            ArrayMap<String, NotificationRecord> recordsByKey
                    = mSnoozedNotifications.get(getPkgKey(userId, pkg));
            if (recordsByKey == null) {
@@ -385,15 +422,20 @@ public class SnoozeHelper {
                mUsers.remove(groupSummaryKey);

                if (record != null && !record.isCanceled) {
                    Runnable runnable = () -> {
                        MetricsLogger.action(record.getLogMaker()
                                .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED)
                                .setType(MetricsProto.MetricsEvent.TYPE_OPEN));
                mCallback.repost(userId, record);
                        mCallback.repost(userId, record, false);
                    };
                    runnable.run();
                }
            }
        }
    }

    protected void clearData(int userId, String pkg) {
        synchronized (mLock) {
            ArrayMap<String, NotificationRecord> records =
                    mSnoozedNotifications.get(getPkgKey(userId, pkg));
            if (records == null) {
@@ -404,11 +446,15 @@ public class SnoozeHelper {
                if (r != null) {
                    mPackages.remove(r.getKey());
                    mUsers.remove(r.getKey());
                    Runnable runnable = () -> {
                        final PendingIntent pi = createPendingIntent(pkg, r.getKey(), userId);
                        mAm.cancel(pi);
                        MetricsLogger.action(r.getLogMaker()
                                .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED)
                                .setType(MetricsProto.MetricsEvent.TYPE_DISMISS));
                    };
                    runnable.run();
                }
            }
        }
    }
@@ -425,6 +471,7 @@ public class SnoozeHelper {
    }

    public void scheduleRepostsForPersistedNotifications(long currentTime) {
        synchronized (mLock) {
            for (ArrayMap<String, Long> snoozed : mPersistedSnoozedNotifications.values()) {
                for (int i = 0; i < snoozed.size(); i++) {
                    String key = snoozed.keyAt(i);
@@ -439,27 +486,31 @@ public class SnoozeHelper {
                        scheduleRepostAtTime(pkg, key, userId, time);
                    }
                }

            }
        }
    }

    private void scheduleRepost(String pkg, String key, int userId, long duration) {
        scheduleRepostAtTime(pkg, key, userId, SystemClock.elapsedRealtime() + duration);
        scheduleRepostAtTime(pkg, key, userId, System.currentTimeMillis() + duration);
    }

    private void scheduleRepostAtTime(String pkg, String key, int userId, long time) {
        Runnable runnable = () -> {
            long identity = Binder.clearCallingIdentity();
            try {
                final PendingIntent pi = createPendingIntent(pkg, key, userId);
                mAm.cancel(pi);
                if (DEBUG) Slog.d(TAG, "Scheduling evaluate for " + new Date(time));
            mAm.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, time, pi);
                mAm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, time, pi);
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        };
        runnable.run();
    }

    public void dump(PrintWriter pw, NotificationManagerService.DumpFilter filter) {
        synchronized (mLock) {
            pw.println("\n  Snoozed notifications:");
            for (String userPkgKey : mSnoozedNotifications.keySet()) {
                pw.print(INDENT);
@@ -494,8 +545,10 @@ public class SnoozeHelper {
                }
            }
        }
    }

    protected void writeXml(XmlSerializer out) throws IOException {
        synchronized (mLock) {
            final long currentTime = System.currentTimeMillis();
            out.startTag(null, XML_TAG_NAME);
            writeXml(out, mPersistedSnoozedNotifications, XML_SNOOZED_NOTIFICATION,
@@ -506,13 +559,15 @@ public class SnoozeHelper {
                        out.attribute(null, XML_SNOOZED_NOTIFICATION_TIME,
                                value.toString());
                    });
        writeXml(out, mPersistedSnoozedNotificationsWithContext, XML_SNOOZED_NOTIFICATION_CONTEXT,
            writeXml(out, mPersistedSnoozedNotificationsWithContext,
                    XML_SNOOZED_NOTIFICATION_CONTEXT,
                    value -> {
                        out.attribute(null, XML_SNOOZED_NOTIFICATION_CONTEXT_ID,
                                value);
                    });
            out.endTag(null, XML_TAG_NAME);
        }
    }

    private interface Inserter<T> {
        void insert(T t) throws IOException;
@@ -522,7 +577,6 @@ public class SnoozeHelper {
            ArrayMap<String, ArrayMap<String, T>> targets, String tag,
            Inserter<T> attributeInserter)
            throws IOException {
        synchronized (targets) {
        final int M = targets.size();
        for (int i = 0; i < M; i++) {
            // T is a String (snoozed until context) or Long (snoozed until time)
@@ -533,6 +587,11 @@ public class SnoozeHelper {
                String pkg = mPackages.get(key);
                Integer userId = mUsers.get(key);

                if (pkg == null || userId == null) {
                    Slog.w(TAG, "pkg " + pkg + " or user " + userId + " missing for " + key);
                    continue;
                }

                out.startTag(null, tag);

                attributeInserter.insert(value);
@@ -550,7 +609,6 @@ public class SnoozeHelper {
            }
        }
    }
    }

    protected void readXml(XmlPullParser parser, long currentTime)
            throws XmlPullParserException, IOException {
@@ -575,16 +633,18 @@ public class SnoozeHelper {
                        final Long time = XmlUtils.readLongAttribute(
                                parser, XML_SNOOZED_NOTIFICATION_TIME, 0);
                        if (time > currentTime) { //only read new stuff
                            synchronized (mPersistedSnoozedNotifications) {
                                storeRecord(pkg, key, userId, mPersistedSnoozedNotifications, time);
                            synchronized (mLock) {
                                storeRecordLocked(
                                        pkg, key, userId, mPersistedSnoozedNotifications, time);
                            }
                        }
                    }
                    if (tag.equals(XML_SNOOZED_NOTIFICATION_CONTEXT)) {
                        final String creationId = parser.getAttributeValue(
                                null, XML_SNOOZED_NOTIFICATION_CONTEXT_ID);
                        synchronized (mPersistedSnoozedNotificationsWithContext) {
                            storeRecord(pkg, key, userId, mPersistedSnoozedNotificationsWithContext,
                        synchronized (mLock) {
                            storeRecordLocked(
                                    pkg, key, userId, mPersistedSnoozedNotificationsWithContext,
                                    creationId);
                        }
                    }
@@ -601,7 +661,7 @@ public class SnoozeHelper {
    }

    protected interface Callback {
        void repost(int userId, NotificationRecord r);
        void repost(int userId, NotificationRecord r, boolean muteOnReturn);
    }

    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -612,7 +672,7 @@ public class SnoozeHelper {
            }
            if (REPOST_ACTION.equals(intent.getAction())) {
                repost(intent.getStringExtra(EXTRA_KEY), intent.getIntExtra(EXTRA_USER_ID,
                        UserHandle.USER_SYSTEM));
                        UserHandle.USER_SYSTEM), false);
            }
        }
    };
+12 −0
Original line number Diff line number Diff line
@@ -845,6 +845,18 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
    }

    @Test
    public void testPostSilently() throws Exception {
        NotificationRecord r = getBuzzyNotification();
        r.setPostSilently(true);

        mService.buzzBeepBlinkLocked(r);

        verifyNeverBeep();
        assertFalse(r.isInterruptive());
        assertEquals(-1, r.getLastAudiblyAlertedMs());
    }

    @Test
    public void testGroupAlertSummarySilenceChild() throws Exception {
        NotificationRecord child = getBeepyNotificationRecord("a", GROUP_ALERT_SUMMARY);
+27 −16

File changed.

Preview size limit exceeded, changes collapsed.