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

Commit e43fac3f authored by Julia Reynolds's avatar Julia Reynolds
Browse files

Add Settings flag to turn notif history on/off

Test: atest
Bug: 137396965
Change-Id: I63af12171c792305a16c6d72e809bf8f15cd215c
parent 0f2b7fd2
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -8155,6 +8155,15 @@ public final class Settings {
        @TestApi
        public static final String NOTIFICATION_BADGING = "notification_badging";
        /**
         * When enabled the system will maintain a rolling history of received notifications. When
         * disabled the history will be disabled and deleted.
         *
         * The value 1 - enable, 0 - disable
         * @hide
         */
        public static final String NOTIFICATION_HISTORY_ENABLED = "notification_history_enabled";
        /**
         * Whether notifications are dismissed by a right-to-left swipe (instead of a left-to-right
         * swipe).
+1 −0
Original line number Diff line number Diff line
@@ -126,6 +126,7 @@ public class SecureSettings {
        Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
        Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS,
        Settings.Secure.SHOW_NOTIFICATION_SNOOZE,
        Settings.Secure.NOTIFICATION_HISTORY_ENABLED,
        Settings.Secure.ZEN_DURATION,
        Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION,
        Settings.Secure.SHOW_ZEN_SETTINGS_SUGGESTION,
+1 −0
Original line number Diff line number Diff line
@@ -182,6 +182,7 @@ public class SecureSettingsValidators {
        VALIDATORS.put(Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, BOOLEAN_VALIDATOR);
        VALIDATORS.put(Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, BOOLEAN_VALIDATOR);
        VALIDATORS.put(Secure.SHOW_NOTIFICATION_SNOOZE, BOOLEAN_VALIDATOR);
        VALIDATORS.put(Secure.NOTIFICATION_HISTORY_ENABLED, BOOLEAN_VALIDATOR);
        VALIDATORS.put(Secure.ZEN_DURATION, ANY_INTEGER_VALIDATOR);
        VALIDATORS.put(Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, BOOLEAN_VALIDATOR);
        VALIDATORS.put(Secure.SHOW_ZEN_SETTINGS_SUGGESTION, BOOLEAN_VALIDATOR);
+8 −0
Original line number Diff line number Diff line
@@ -223,6 +223,13 @@ public class NotificationHistoryDatabase {
        }
    }

    public void disableHistory() {
        synchronized (mLock) {
            mHistoryDir.delete();
            mHistoryFiles.clear();
        }
    }

    /**
     * Remove any files that are too old and schedule jobs to clean up the rest
     */
@@ -241,6 +248,7 @@ public class NotificationHistoryDatabase {
                        Slog.d(TAG, "Removed " + currentOldestFile.getBaseFile().getName());
                    }
                    currentOldestFile.delete();
                    // TODO: delete all relevant bitmaps, once they exist
                    mHistoryFiles.removeLast();
                } else {
                    // all remaining files are newer than the cut off; schedule jobs to delete
+98 −10
Original line number Diff line number Diff line
@@ -21,9 +21,16 @@ import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.NotificationHistory;
import android.app.NotificationHistory.HistoricalNotification;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -49,6 +56,8 @@ public class NotificationHistoryManager {

    private final Context mContext;
    private final UserManager mUserManager;
    @VisibleForTesting
    final SettingsObserver mSettingsObserver;
    private final Object mLock = new Object();
    @GuardedBy("mLock")
    private final SparseArray<NotificationHistoryDatabase> mUserState = new SparseArray<>();
@@ -57,19 +66,26 @@ public class NotificationHistoryManager {
    // TODO: does this need to be persisted across reboots?
    @GuardedBy("mLock")
    private final SparseArray<List<String>> mUserPendingPackageRemovals = new SparseArray<>();
    @GuardedBy("mLock")
    private final SparseBooleanArray mHistoryEnabled = new SparseBooleanArray();

    public NotificationHistoryManager(Context context) {
    public NotificationHistoryManager(Context context, Handler handler) {
        mContext = context;
        mUserManager = context.getSystemService(UserManager.class);
        mSettingsObserver = new SettingsObserver(handler);
    }

    public void onUserUnlocked(@UserIdInt int userId) {
    void onBootPhaseAppsCanStart() {
        mSettingsObserver.observe();
    }

    void onUserUnlocked(@UserIdInt int userId) {
        synchronized (mLock) {
            mUserUnlockedStates.put(userId, true);
            final NotificationHistoryDatabase userHistory =
                    getUserHistoryAndInitializeIfNeededLocked(userId);
            if (userHistory == null) {
                Slog.i(TAG, "Attempted to unlock stopped or removed user " + userId);
                Slog.i(TAG, "Attempted to unlock gone/disabled user " + userId);
                return;
            }

@@ -81,6 +97,11 @@ public class NotificationHistoryManager {
                }
                mUserPendingPackageRemovals.put(userId, null);
            }

            // delete history if it was disabled when the user was locked
            if (!mHistoryEnabled.get(userId)) {
                userHistory.disableHistory();
            }
        }
    }

@@ -96,6 +117,7 @@ public class NotificationHistoryManager {
            // Actual data deletion is handled by other parts of the system (the entire directory is
            // removed) - we just need clean up our internal state for GC
            mUserPendingPackageRemovals.put(userId, null);
            mHistoryEnabled.put(userId, false);
            onUserStopped(userId);
        }
    }
@@ -103,10 +125,12 @@ public class NotificationHistoryManager {
    void onPackageRemoved(int userId, String packageName) {
        synchronized (mLock) {
            if (!mUserUnlockedStates.get(userId, false)) {
                if (mHistoryEnabled.get(userId, false)) {
                    List<String> userPendingRemovals =
                            mUserPendingPackageRemovals.get(userId, new ArrayList<>());
                    userPendingRemovals.add(packageName);
                    mUserPendingPackageRemovals.put(userId, userPendingRemovals);
                }
                return;
            }
            final NotificationHistoryDatabase userHistory = mUserState.get(userId);
@@ -139,7 +163,7 @@ public class NotificationHistoryManager {
            final NotificationHistoryDatabase userHistory =
                    getUserHistoryAndInitializeIfNeededLocked(notification.getUserId());
            if (userHistory == null) {
                Slog.w(TAG, "Attempted to add notif for locked/gone user "
                Slog.w(TAG, "Attempted to add notif for locked/gone/disabled user "
                        + notification.getUserId());
                return;
            }
@@ -157,7 +181,7 @@ public class NotificationHistoryManager {
                final NotificationHistoryDatabase userHistory =
                        getUserHistoryAndInitializeIfNeededLocked(userId);
                if (userHistory == null) {
                    Slog.i(TAG, "Attempted to read history for locked/gone user " +userId);
                    Slog.i(TAG, "Attempted to read history for locked/gone/disabled user " +userId);
                    continue;
                }
                mergedHistory.addNotificationsToWrite(userHistory.readNotificationHistory());
@@ -172,7 +196,7 @@ public class NotificationHistoryManager {
            final NotificationHistoryDatabase userHistory =
                    getUserHistoryAndInitializeIfNeededLocked(userId);
            if (userHistory == null) {
                Slog.i(TAG, "Attempted to read history for locked/gone user " +userId);
                Slog.i(TAG, "Attempted to read history for locked/gone/disabled user " +userId);
                return new android.app.NotificationHistory();
            }

@@ -180,9 +204,38 @@ public class NotificationHistoryManager {
        }
    }

    public boolean isHistoryEnabled(@UserIdInt int userId) {
        synchronized (mLock) {
            return mHistoryEnabled.get(userId);
        }
    }

    void onHistoryEnabledChanged(@UserIdInt int userId, boolean historyEnabled) {
        synchronized (mLock) {
            mHistoryEnabled.put(userId, historyEnabled);

            // These requests might fail if the user is locked; onUserUnlocked will pick up those
            // cases
            final NotificationHistoryDatabase userHistory =
                    getUserHistoryAndInitializeIfNeededLocked(userId);
            if (userHistory != null) {
                if (!historyEnabled) {
                    userHistory.disableHistory();
                }
            }
        }
    }

    @GuardedBy("mLock")
    private @Nullable NotificationHistoryDatabase getUserHistoryAndInitializeIfNeededLocked(
            int userId) {
        if (!mHistoryEnabled.get(userId)) {
            if (DEBUG) {
                Slog.i(TAG, "History disabled for user " + userId);
            }
            mUserState.put(userId, null);
            return null;
        }
        NotificationHistoryDatabase userHistory = mUserState.get(userId);
        if (userHistory == null) {
            final File historyDir = new File(Environment.getDataSystemCeDirectory(userId),
@@ -242,4 +295,39 @@ public class NotificationHistoryManager {
            return mUserPendingPackageRemovals.get(userId);
        }
    }

    final class SettingsObserver extends ContentObserver {
        private final Uri NOTIFICATION_HISTORY_URI
                = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_HISTORY_ENABLED);

        SettingsObserver(Handler handler) {
            super(handler);
        }

        void observe() {
            ContentResolver resolver = mContext.getContentResolver();
            resolver.registerContentObserver(NOTIFICATION_HISTORY_URI,
                    false, this, UserHandle.USER_ALL);
            synchronized (mLock) {
                for (UserInfo userInfo : mUserManager.getUsers()) {
                    update(null, userInfo.id);
                }
            }
        }

        @Override
        public void onChange(boolean selfChange, Uri uri, int userId) {
            update(uri, userId);
        }

        public void update(Uri uri, int userId) {
            ContentResolver resolver = mContext.getContentResolver();
            if (uri == null || NOTIFICATION_HISTORY_URI.equals(uri)) {
                boolean historyEnabled = Settings.Secure.getIntForUser(resolver,
                        Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, userId)
                        != 0;
                onHistoryEnabledChanged(userId, historyEnabled);
            }
        }
    }
}
Loading