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

Commit 7219adad authored by Bryce Lee's avatar Bryce Lee
Browse files

Add granular control over disabled effects.

Currently, we can only wholesale disable effects outside of zen mode.
There are some devices that require long running suppression of features.
Effects disabling was added previously to support this. However, calling
suppression was broken recently on a device where we needed notification
suppression, but not calling suppression.

This CL remedies this problem by adding more granular disabled effects
hints. The NotificationManagerService has been updated to handle these
request types and present ZenModeHelper with a unified map of what should
be suppressed.

Bug: 27992763
Change-Id: I38b4706446dfd6e1c3eb97266dbc3332b250adda
parent 50a2d43b
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -34693,7 +34693,9 @@ package android.service.notification {
    method public static void requestRebind(android.content.ComponentName) throws android.os.RemoteException;
    method public final void requestUnbind() throws android.os.RemoteException;
    method public final void setNotificationsShown(java.lang.String[]);
    field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4
    field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
    field public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 2; // 0x2
    field public static final int INTERRUPTION_FILTER_ALARMS = 4; // 0x4
    field public static final int INTERRUPTION_FILTER_ALL = 1; // 0x1
    field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3
+2 −0
Original line number Diff line number Diff line
@@ -37176,7 +37176,9 @@ package android.service.notification {
    method public final void setNotificationsShown(java.lang.String[]);
    method public final void setOnNotificationPostedTrim(int);
    method public void unregisterAsSystemService() throws android.os.RemoteException;
    field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4
    field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
    field public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 2; // 0x2
    field public static final int INTERRUPTION_FILTER_ALARMS = 4; // 0x4
    field public static final int INTERRUPTION_FILTER_ALL = 1; // 0x1
    field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3
+2 −0
Original line number Diff line number Diff line
@@ -34765,7 +34765,9 @@ package android.service.notification {
    method public static void requestRebind(android.content.ComponentName) throws android.os.RemoteException;
    method public final void requestUnbind() throws android.os.RemoteException;
    method public final void setNotificationsShown(java.lang.String[]);
    field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4
    field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
    field public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 2; // 0x2
    field public static final int INTERRUPTION_FILTER_ALARMS = 4; // 0x4
    field public static final int INTERRUPTION_FILTER_ALL = 1; // 0x1
    field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3
+10 −0
Original line number Diff line number Diff line
@@ -117,6 +117,16 @@ public abstract class NotificationListenerService extends Service {
     * This does not change the interruption filter, only the effects. **/
    public static final int HINT_HOST_DISABLE_EFFECTS = 1;

    /** {@link #getCurrentListenerHints() Listener hints} constant - the primary device UI
     * should disable notification sound, but not phone calls.
     * This does not change the interruption filter, only the effects. **/
    public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 1 << 1;

    /** {@link #getCurrentListenerHints() Listener hints} constant - the primary device UI
     * should disable phone call sounds, buyt not notification sound.
     * This does not change the interruption filter, only the effects. **/
    public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 1 << 2;

    /**
     * Whether notification suppressed by DND should not interruption visually when the screen is
     * off.
+124 −18
Original line number Diff line number Diff line
@@ -32,6 +32,8 @@ import static android.service.notification.NotificationRankerService.REASON_PACK
import static android.service.notification.NotificationRankerService.REASON_PROFILE_TURNED_OFF;
import static android.service.notification.NotificationRankerService.REASON_USER_STOPPED;
import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
import static android.service.notification.NotificationListenerService.TRIM_FULL;
@@ -114,6 +116,7 @@ import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -248,8 +251,9 @@ public class NotificationManagerService extends SystemService {
    private String mSoundNotificationKey;
    private String mVibrateNotificationKey;

    private final ArraySet<ManagedServiceInfo> mListenersDisablingEffects = new ArraySet<>();
    private ComponentName mEffectsSuppressor;
    private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
            new SparseArray<ArraySet<ManagedServiceInfo>>();
    private List<ComponentName> mEffectsSuppressors = new ArrayList<ComponentName>();
    private int mListenerHints;  // right now, all hints are global
    private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;

@@ -1119,23 +1123,112 @@ public class NotificationManagerService extends SystemService {
    }

    private void updateListenerHintsLocked() {
        final int hints = mListenersDisablingEffects.isEmpty() ? 0 : HINT_HOST_DISABLE_EFFECTS;
        final int hints = calculateHints();
        if (hints == mListenerHints) return;
        ZenLog.traceListenerHintsChanged(mListenerHints, hints, mListenersDisablingEffects.size());
        ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
        mListenerHints = hints;
        scheduleListenerHintsChanged(hints);
    }

    private void updateEffectsSuppressorLocked() {
        final ComponentName suppressor = !mListenersDisablingEffects.isEmpty()
                ? mListenersDisablingEffects.valueAt(0).component : null;
        if (Objects.equals(suppressor, mEffectsSuppressor)) return;
        ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressor, suppressor);
        mEffectsSuppressor = suppressor;
        mZenModeHelper.setEffectsSuppressed(suppressor != null);
        final long updatedSuppressedEffects = calculateSuppressedEffects();
        if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
        final List<ComponentName> suppressors = getSuppressors();
        ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
        mEffectsSuppressors = suppressors;
        mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
        sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
    }

    private ArrayList<ComponentName> getSuppressors() {
        ArrayList<ComponentName> names = new ArrayList<ComponentName>();
        for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
            ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);

            for (ManagedServiceInfo info : serviceInfoList) {
                names.add(info.component);
            }
        }

        return names;
    }

    private boolean removeDisabledHints(ManagedServiceInfo info) {
        return removeDisabledHints(info, 0);
    }

    private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
        boolean removed = false;

        for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
            final int hint = mListenersDisablingEffects.keyAt(i);
            final ArraySet<ManagedServiceInfo> listeners =
                    mListenersDisablingEffects.valueAt(i);

            if (hints == 0 || (hint & hints) == hint) {
                removed = removed || listeners.remove(info);
            }
        }

        return removed;
    }

    private void addDisabledHints(ManagedServiceInfo info, int hints) {
        if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
            addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
        }

        if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
            addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
        }

        if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
            addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
        }
    }

    private void addDisabledHint(ManagedServiceInfo info, int hint) {
        if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
            mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
        }

        ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
        hintListeners.add(info);
    }

    private int calculateHints() {
        int hints = 0;
        for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
            int hint = mListenersDisablingEffects.keyAt(i);
            ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);

            if (!serviceInfoList.isEmpty()) {
                hints |= hint;
            }
        }

        return hints;
    }

    private long calculateSuppressedEffects() {
        int hints = calculateHints();
        long suppressedEffects = 0;

        if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
            suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
        }

        if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
            suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
        }

        if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
            suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
        }

        return suppressedEffects;
    }

    private void updateInterruptionFilterLocked() {
        int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
        if (interruptionFilter == mInterruptionFilter) return;
@@ -1652,11 +1745,14 @@ public class NotificationManagerService extends SystemService {
            try {
                synchronized (mNotificationList) {
                    final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
                    final boolean disableEffects = (hints & HINT_HOST_DISABLE_EFFECTS) != 0;
                    final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
                            | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
                            | HINT_HOST_DISABLE_CALL_EFFECTS;
                    final boolean disableEffects = (hints & disableEffectsMask) != 0;
                    if (disableEffects) {
                        mListenersDisablingEffects.add(info);
                        addDisabledHints(info, hints);
                    } else {
                        mListenersDisablingEffects.remove(info);
                        removeDisabledHints(info, hints);
                    }
                    updateListenerHintsLocked();
                    updateEffectsSuppressorLocked();
@@ -1914,7 +2010,7 @@ public class NotificationManagerService extends SystemService {
        @Override
        public ComponentName getEffectsSuppressor() {
            enforceSystemOrSystemUIOrVolume("INotificationManager.getEffectsSuppressor");
            return mEffectsSuppressor;
            return mEffectsSuppressors.get(0);
        }

        @Override
@@ -2176,10 +2272,20 @@ public class NotificationManagerService extends SystemService {
                pw.print("    mListenersDisablingEffects: (");
                N = mListenersDisablingEffects.size();
                for (int i = 0; i < N; i++) {
                    final ManagedServiceInfo listener = mListenersDisablingEffects.valueAt(i);
                    final int hint = mListenersDisablingEffects.keyAt(i);
                    if (i > 0) pw.print(';');
                    pw.print("hint[" + hint + "]:");

                    final ArraySet<ManagedServiceInfo> listeners =
                            mListenersDisablingEffects.valueAt(i);
                    final int listenerSize = listeners.size();

                    for (int j = 0; j < listenerSize; j++) {
                        if (i > 0) pw.print(',');
                        final ManagedServiceInfo listener = listeners.valueAt(i);
                        pw.print(listener.component);
                    }
                }
                pw.println(')');
                pw.println("\n  mRankerServicePackageName: " + mRankerServicePackageName);
                pw.println("\n  Notification ranker services:");
@@ -3690,7 +3796,7 @@ public class NotificationManagerService extends SystemService {

        @Override
        protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
            if (mListenersDisablingEffects.remove(removed)) {
            if (removeDisabledHints(removed)) {
                updateListenerHintsLocked();
                updateEffectsSuppressorLocked();
            }
Loading