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

Commit 0350dab5 authored by Rohan Shah's avatar Rohan Shah
Browse files

Add knobs for tweaking blocking helper thresholds

Added both blocking helper parameters to Global Settings to allow for
tweaking stats/values. Added listeners for value updates (so that
channels are updated properly with new thresholds).

Bug: 77143005
Test: manually, test cases
Change-Id: Ia5cfb29ca40500a694261bd5e9e60fa1f34e742a
parent 530c4c1f
Loading
Loading
Loading
Loading
+23 −1
Original line number Original line Diff line number Diff line
@@ -12561,6 +12561,28 @@ public final class Settings {
        public static final String NOTIFICATION_SNOOZE_OPTIONS =
        public static final String NOTIFICATION_SNOOZE_OPTIONS =
                "notification_snooze_options";
                "notification_snooze_options";
        /**
         * Settings key for the ratio of notification dismissals to notification views - one of the
         * criteria for showing the notification blocking helper.
         *
         * <p>The value is a float ranging from 0.0 to 1.0 (the closer to 0.0, the more intrusive
         * the blocking helper will be).
         *
         * @hide
         */
        public static final String BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT =
                "blocking_helper_dismiss_to_view_ratio";
        /**
         * Settings key for the longest streak of dismissals  - one of the criteria for showing the
         * notification blocking helper.
         *
         * <p>The value is an integer greater than 0.
         *
         * @hide
         */
        public static final String BLOCKING_HELPER_STREAK_LIMIT = "blocking_helper_streak_limit";
        /**
        /**
         * Configuration flags for SQLite Compatibility WAL. Encoded as a key-value list, separated
         * Configuration flags for SQLite Compatibility WAL. Encoded as a key-value list, separated
         * by commas. E.g.: compatibility_wal_supported=true, wal_syncmode=OFF
         * by commas. E.g.: compatibility_wal_supported=true, wal_syncmode=OFF
+4 −1
Original line number Original line Diff line number Diff line
@@ -48,7 +48,10 @@ public abstract class NotificationAssistantService extends NotificationListenerS
    public static final String SERVICE_INTERFACE
    public static final String SERVICE_INTERFACE
            = "android.service.notification.NotificationAssistantService";
            = "android.service.notification.NotificationAssistantService";


    private Handler mHandler;
    /**
     * @hide
     */
    protected Handler mHandler;


    @Override
    @Override
    protected void attachBaseContext(Context base) {
    protected void attachBaseContext(Context base) {
+2 −0
Original line number Original line Diff line number Diff line
@@ -131,6 +131,8 @@ public class SettingsBackupTest {
                    Settings.Global.BLE_SCAN_LOW_LATENCY_WINDOW_MS,
                    Settings.Global.BLE_SCAN_LOW_LATENCY_WINDOW_MS,
                    Settings.Global.BLE_SCAN_LOW_LATENCY_INTERVAL_MS,
                    Settings.Global.BLE_SCAN_LOW_LATENCY_INTERVAL_MS,
                    Settings.Global.BLE_SCAN_BACKGROUND_MODE,
                    Settings.Global.BLE_SCAN_BACKGROUND_MODE,
                    Settings.Global.BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT,
                    Settings.Global.BLOCKING_HELPER_STREAK_LIMIT,
                    Settings.Global.BLUETOOTH_A2DP_SINK_PRIORITY_PREFIX,
                    Settings.Global.BLUETOOTH_A2DP_SINK_PRIORITY_PREFIX,
                    Settings.Global.BLUETOOTH_A2DP_SRC_PRIORITY_PREFIX,
                    Settings.Global.BLUETOOTH_A2DP_SRC_PRIORITY_PREFIX,
                    Settings.Global.BLUETOOTH_A2DP_SUPPORTS_OPTIONAL_CODECS_PREFIX,
                    Settings.Global.BLUETOOTH_A2DP_SUPPORTS_OPTIONAL_CODECS_PREFIX,
+75 −6
Original line number Original line Diff line number Diff line
@@ -17,16 +17,20 @@
package android.ext.services.notification;
package android.ext.services.notification;


import static android.app.NotificationManager.IMPORTANCE_MIN;
import static android.app.NotificationManager.IMPORTANCE_MIN;
import static android.service.notification.NotificationListenerService.Ranking
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
        .USER_SENTIMENT_NEGATIVE;


import android.app.INotificationManager;
import android.app.INotificationManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Context;
import android.database.ContentObserver;
import android.ext.services.R;
import android.ext.services.R;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Bundle;
import android.os.Environment;
import android.os.Environment;
import android.os.Handler;
import android.os.storage.StorageManager;
import android.os.storage.StorageManager;
import android.provider.Settings;
import android.service.notification.Adjustment;
import android.service.notification.Adjustment;
import android.service.notification.NotificationAssistantService;
import android.service.notification.NotificationAssistantService;
import android.service.notification.NotificationStats;
import android.service.notification.NotificationStats;
@@ -74,9 +78,12 @@ public class Assistant extends NotificationAssistantService {
        PREJUDICAL_DISMISSALS.add(REASON_LISTENER_CANCEL);
        PREJUDICAL_DISMISSALS.add(REASON_LISTENER_CANCEL);
    }
    }


    private float mDismissToViewRatioLimit;
    private int mStreakLimit;

    // key : impressions tracker
    // key : impressions tracker
    // TODO: prune deleted channels and apps
    // TODO: prune deleted channels and apps
    ArrayMap<String, ChannelImpressions> mkeyToImpressions = new ArrayMap<>();
    final ArrayMap<String, ChannelImpressions> mkeyToImpressions = new ArrayMap<>();
    // SBN key : channel id
    // SBN key : channel id
    ArrayMap<String, String> mLiveNotifications = new ArrayMap<>();
    ArrayMap<String, String> mLiveNotifications = new ArrayMap<>();


@@ -86,6 +93,14 @@ public class Assistant extends NotificationAssistantService {
    public Assistant() {
    public Assistant() {
    }
    }


    @Override
    public void onCreate() {
        super.onCreate();
        // Contexts are correctly hooked up by the creation step, which is required for the observer
        // to be hooked up/initialized.
        new SettingsObserver(mHandler);
    }

    private void loadFile() {
    private void loadFile() {
        if (DEBUG) Slog.d(TAG, "loadFile");
        if (DEBUG) Slog.d(TAG, "loadFile");
        AsyncTask.execute(() -> {
        AsyncTask.execute(() -> {
@@ -120,7 +135,7 @@ public class Assistant extends NotificationAssistantService {
                    continue;
                    continue;
                }
                }
                String key = parser.getAttributeValue(null, ATT_KEY);
                String key = parser.getAttributeValue(null, ATT_KEY);
                ChannelImpressions ci = new ChannelImpressions();
                ChannelImpressions ci = createChannelImpressionsWithThresholds();
                ci.populateFromXml(parser);
                ci.populateFromXml(parser);
                synchronized (mkeyToImpressions) {
                synchronized (mkeyToImpressions) {
                    ci.append(mkeyToImpressions.get(key));
                    ci.append(mkeyToImpressions.get(key));
@@ -184,7 +199,7 @@ public class Assistant extends NotificationAssistantService {
                String key = getKey(
                String key = getKey(
                        sbn.getPackageName(), sbn.getUserId(), ranking.getChannel().getId());
                        sbn.getPackageName(), sbn.getUserId(), ranking.getChannel().getId());
                ChannelImpressions ci = mkeyToImpressions.getOrDefault(key,
                ChannelImpressions ci = mkeyToImpressions.getOrDefault(key,
                        new ChannelImpressions());
                        createChannelImpressionsWithThresholds());
                if (ranking.getImportance() > IMPORTANCE_MIN && ci.shouldTriggerBlock()) {
                if (ranking.getImportance() > IMPORTANCE_MIN && ci.shouldTriggerBlock()) {
                    adjustNotification(createNegativeAdjustment(
                    adjustNotification(createNegativeAdjustment(
                            sbn.getPackageName(), sbn.getKey(), sbn.getUserId()));
                            sbn.getPackageName(), sbn.getKey(), sbn.getUserId()));
@@ -206,7 +221,7 @@ public class Assistant extends NotificationAssistantService {
            String key = getKey(sbn.getPackageName(), sbn.getUserId(), channelId);
            String key = getKey(sbn.getPackageName(), sbn.getUserId(), channelId);
            synchronized (mkeyToImpressions) {
            synchronized (mkeyToImpressions) {
                ChannelImpressions ci = mkeyToImpressions.getOrDefault(key,
                ChannelImpressions ci = mkeyToImpressions.getOrDefault(key,
                        new ChannelImpressions());
                        createChannelImpressionsWithThresholds());
                if (stats.hasSeen()) {
                if (stats.hasSeen()) {
                    ci.incrementViews();
                    ci.incrementViews();
                    updatedImpressions = true;
                    updatedImpressions = true;
@@ -310,4 +325,58 @@ public class Assistant extends NotificationAssistantService {
            mkeyToImpressions.put(key, ci);
            mkeyToImpressions.put(key, ci);
        }
        }
    }
    }

    private ChannelImpressions createChannelImpressionsWithThresholds() {
        ChannelImpressions impressions = new ChannelImpressions();
        impressions.updateThresholds(mDismissToViewRatioLimit, mStreakLimit);
        return impressions;
    }

    /**
     * Observer for updates on blocking helper threshold values.
     */
    private final class SettingsObserver extends ContentObserver {
        private final Uri STREAK_LIMIT_URI =
                Settings.Global.getUriFor(Settings.Global.BLOCKING_HELPER_STREAK_LIMIT);
        private final Uri DISMISS_TO_VIEW_RATIO_LIMIT_URI =
                Settings.Global.getUriFor(
                        Settings.Global.BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT);

        public SettingsObserver(Handler handler) {
            super(handler);
            ContentResolver resolver = getApplicationContext().getContentResolver();
            resolver.registerContentObserver(
                    DISMISS_TO_VIEW_RATIO_LIMIT_URI, false, this, getUserId());
            resolver.registerContentObserver(STREAK_LIMIT_URI, false, this, getUserId());

            // Update all uris on creation.
            update(null);
        }

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

        private void update(Uri uri) {
            ContentResolver resolver = getApplicationContext().getContentResolver();
            if (uri == null || DISMISS_TO_VIEW_RATIO_LIMIT_URI.equals(uri)) {
                mDismissToViewRatioLimit = Settings.Global.getFloat(
                        resolver, Settings.Global.BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT,
                        ChannelImpressions.DEFAULT_DISMISS_TO_VIEW_RATIO_LIMIT);
            }
            if (uri == null || STREAK_LIMIT_URI.equals(uri)) {
                mStreakLimit = Settings.Global.getInt(
                        resolver, Settings.Global.BLOCKING_HELPER_STREAK_LIMIT,
                        ChannelImpressions.DEFAULT_STREAK_LIMIT);
            }

            // Update all existing channel impression objects with any new limits/thresholds.
            synchronized (mkeyToImpressions) {
                for (ChannelImpressions channelImpressions: mkeyToImpressions.values()) {
                    channelImpressions.updateThresholds(mDismissToViewRatioLimit, mStreakLimit);
                }
            }
        }
    }
}
}
 No newline at end of file
+33 −10
Original line number Original line Diff line number Diff line
@@ -21,6 +21,8 @@ import android.os.Parcelable;
import android.text.TextUtils;
import android.text.TextUtils;
import android.util.Log;
import android.util.Log;


import com.android.internal.annotations.VisibleForTesting;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
import org.xmlpull.v1.XmlSerializer;


@@ -30,8 +32,8 @@ public final class ChannelImpressions implements Parcelable {
    private static final String TAG = "ExtAssistant.CI";
    private static final String TAG = "ExtAssistant.CI";
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);


    static final double DISMISS_TO_VIEW_RATIO_LIMIT = .4;
    static final float DEFAULT_DISMISS_TO_VIEW_RATIO_LIMIT = .4f;
    static final int STREAK_LIMIT = 2;
    static final int DEFAULT_STREAK_LIMIT = 2;
    static final String ATT_DISMISSALS = "dismisses";
    static final String ATT_DISMISSALS = "dismisses";
    static final String ATT_VIEWS = "views";
    static final String ATT_VIEWS = "views";
    static final String ATT_STREAK = "streak";
    static final String ATT_STREAK = "streak";
@@ -40,18 +42,20 @@ public final class ChannelImpressions implements Parcelable {
    private int mViews = 0;
    private int mViews = 0;
    private int mStreak = 0;
    private int mStreak = 0;


    public ChannelImpressions() {
    private float mDismissToViewRatioLimit;
    }
    private int mStreakLimit;


    public ChannelImpressions(int dismissals, int views) {
    public ChannelImpressions() {
        mDismissals = dismissals;
        mDismissToViewRatioLimit = DEFAULT_DISMISS_TO_VIEW_RATIO_LIMIT;
        mViews = views;
        mStreakLimit = DEFAULT_STREAK_LIMIT;
    }
    }


    protected ChannelImpressions(Parcel in) {
    protected ChannelImpressions(Parcel in) {
        mDismissals = in.readInt();
        mDismissals = in.readInt();
        mViews = in.readInt();
        mViews = in.readInt();
        mStreak = in.readInt();
        mStreak = in.readInt();
        mDismissToViewRatioLimit = in.readFloat();
        mStreakLimit = in.readInt();
    }
    }


    public int getStreak() {
    public int getStreak() {
@@ -71,6 +75,21 @@ public final class ChannelImpressions implements Parcelable {
        mStreak++;
        mStreak++;
    }
    }


    void updateThresholds(float dismissToViewRatioLimit, int streakLimit) {
        mDismissToViewRatioLimit = dismissToViewRatioLimit;
        mStreakLimit = streakLimit;
    }

    @VisibleForTesting
    float getDismissToViewRatioLimit() {
        return mDismissToViewRatioLimit;
    }

    @VisibleForTesting
    int getStreakLimit() {
        return mStreakLimit;
    }

    public void append(ChannelImpressions additionalImpressions) {
    public void append(ChannelImpressions additionalImpressions) {
        if (additionalImpressions != null) {
        if (additionalImpressions != null) {
            mViews += additionalImpressions.getViews();
            mViews += additionalImpressions.getViews();
@@ -94,8 +113,8 @@ public final class ChannelImpressions implements Parcelable {
        if (DEBUG) {
        if (DEBUG) {
            Log.d(TAG, "should trigger? " + getDismissals() + " " + getViews() + " " + getStreak());
            Log.d(TAG, "should trigger? " + getDismissals() + " " + getViews() + " " + getStreak());
        }
        }
        return ((double) getDismissals() / getViews()) > DISMISS_TO_VIEW_RATIO_LIMIT
        return ((float) getDismissals() / getViews()) > mDismissToViewRatioLimit
                && getStreak() > STREAK_LIMIT;
                && getStreak() > mStreakLimit;
    }
    }


    @Override
    @Override
@@ -103,6 +122,8 @@ public final class ChannelImpressions implements Parcelable {
        dest.writeInt(mDismissals);
        dest.writeInt(mDismissals);
        dest.writeInt(mViews);
        dest.writeInt(mViews);
        dest.writeInt(mStreak);
        dest.writeInt(mStreak);
        dest.writeFloat(mDismissToViewRatioLimit);
        dest.writeInt(mStreakLimit);
    }
    }


    @Override
    @Override
@@ -148,7 +169,9 @@ public final class ChannelImpressions implements Parcelable {
        sb.append("mDismissals=").append(mDismissals);
        sb.append("mDismissals=").append(mDismissals);
        sb.append(", mViews=").append(mViews);
        sb.append(", mViews=").append(mViews);
        sb.append(", mStreak=").append(mStreak);
        sb.append(", mStreak=").append(mStreak);
        sb.append('}');
        sb.append(", thresholds=(").append(mDismissToViewRatioLimit);
        sb.append(",").append(mStreakLimit);
        sb.append(")}");
        return sb.toString();
        return sb.toString();
    }
    }


Loading