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

Commit 7c9fbcc6 authored by Julia Reynolds's avatar Julia Reynolds
Browse files

Adds an NLS api for telling the OS what notifs types they bridge

If an app doesn't bridge a particular type of notification
we will disabled in Settings so users understand why they aren't
seeing those types of notifications on paired devices.

Test: CTS, Settings unit
Bug: 181125165
Change-Id: I6e702898c3e682f732e91c4a4e02b96ff16b7077
parent 2409543c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -38534,6 +38534,7 @@ package android.service.notification {
    field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2
    field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
    field public static final String META_DATA_DEFAULT_FILTER_TYPES = "android.service.notification.default_filter_types";
    field public static final String META_DATA_DISABLED_FILTER_TYPES = "android.service.notification.disabled_filter_types";
    field public static final int NOTIFICATION_CHANNEL_OR_GROUP_ADDED = 1; // 0x1
    field public static final int NOTIFICATION_CHANNEL_OR_GROUP_DELETED = 3; // 0x3
    field public static final int NOTIFICATION_CHANNEL_OR_GROUP_UPDATED = 2; // 0x2
+17 −0
Original line number Diff line number Diff line
@@ -85,6 +85,10 @@ import java.util.Objects;
 *               android:name="android.service.notification.default_filter_types"
 *               android:value="1,2">
 *           </meta-data>
 *     <meta-data
 *               android:name="android.service.notification.disabled_filter_types"
 *               android:value="2">
 *           </meta-data>
 * &lt;/service></pre>
 *
 * <p>The service should wait for the {@link #onListenerConnected()} event
@@ -122,6 +126,19 @@ public abstract class NotificationListenerService extends Service {
    public static final String META_DATA_DEFAULT_FILTER_TYPES
            = "android.service.notification.default_filter_types";

    /**
     * The name of the {@code meta-data} tag containing a comma separated list of default
     * integer notification types that this listener never wants to receive. See
     * {@link #FLAG_FILTER_TYPE_ONGOING},
     * {@link #FLAG_FILTER_TYPE_CONVERSATIONS}, {@link #FLAG_FILTER_TYPE_ALERTING),
     * and {@link #FLAG_FILTER_TYPE_SILENT}.
     * <p>Types provided in this list will appear as 'off' and 'disabled' in the user interface,
     * so users don't enable a type that the listener will never bridge to their paired devices.</p>
     *
     */
    public static final String META_DATA_DISABLED_FILTER_TYPES
            = "android.service.notification.disabled_filter_types";

    /**
     * {@link #getCurrentInterruptionFilter() Interruption filter} constant -
     *     Normal interruption filter.
+42 −19
Original line number Diff line number Diff line
@@ -73,6 +73,8 @@ import static android.service.notification.NotificationListenerService.FLAG_FILT
import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
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.META_DATA_DEFAULT_FILTER_TYPES;
import static android.service.notification.NotificationListenerService.META_DATA_DISABLED_FILTER_TYPES;
import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
@@ -9859,13 +9861,39 @@ public class NotificationManagerService extends SystemService {
            Pair listener = Pair.create(si.getComponentName(), userId);
            NotificationListenerFilter existingNlf =
                    mRequestedNotificationListeners.get(listener);
            if (si.metaData != null) {
                if (existingNlf  == null) {
                    // no stored filters for this listener; see if they provided a default
                if (si.metaData != null) {
                    String typeList = si.metaData.getString(
                            NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES);
                    if (si.metaData.containsKey(META_DATA_DEFAULT_FILTER_TYPES)) {
                        String typeList =
                                si.metaData.get(META_DATA_DEFAULT_FILTER_TYPES).toString();
                        if (typeList != null) {
                            int types = getTypesFromStringList(typeList);
                            NotificationListenerFilter nlf =
                                    new NotificationListenerFilter(types, new ArraySet<>());
                            mRequestedNotificationListeners.put(listener, nlf);
                        }
                    }
                }

                // also check the types they never want bridged
                if (si.metaData.containsKey(META_DATA_DISABLED_FILTER_TYPES)) {
                    int neverBridge = getTypesFromStringList(si.metaData.get(
                            META_DATA_DISABLED_FILTER_TYPES).toString());
                    if (neverBridge != 0) {
                        NotificationListenerFilter nlf =
                                mRequestedNotificationListeners.getOrDefault(
                                        listener, new NotificationListenerFilter());
                        nlf.setTypes(nlf.getTypes() & ~neverBridge);
                        mRequestedNotificationListeners.put(listener, nlf);
                    }
                }
            }
        }

        private int getTypesFromStringList(String typeList) {
            int types = 0;
            if (typeList != null) {
                String[] typeStrings = typeList.split(XML_SEPARATOR);
                for (int i = 0; i < typeStrings.length; i++) {
                    if (TextUtils.isEmpty(typeStrings[i])) {
@@ -9877,13 +9905,8 @@ public class NotificationManagerService extends SystemService {
                        // skip
                    }
                }

                         NotificationListenerFilter nlf =
                                 new NotificationListenerFilter(types, new ArraySet<>());
                        mRequestedNotificationListeners.put(listener, nlf);
                    }
                }
            }
            return types;
        }

        @GuardedBy("mNotificationLock")
+48 −0
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@ package com.android.server.notification;

import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_SILENT;

import static com.android.server.notification.NotificationManagerService.NotificationListeners.TAG_REQUESTED_LISTENERS;

@@ -204,6 +206,52 @@ public class NotificationListenersTest extends UiServiceTestCase {
                .isEqualTo(FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ALERTING);
    }

    @Test
    public void testEnsureFilters_newServiceWithMetadata_onlyOneListed() {
        ServiceInfo si = new ServiceInfo();
        si.packageName = "new";
        si.name = "comp";
        si.metaData = new Bundle();
        si.metaData.putInt(NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES, 2);

        mListeners.ensureFilters(si, 0);

        assertThat(mListeners.getNotificationListenerFilter(
                Pair.create(si.getComponentName(), 0)).getTypes())
                .isEqualTo(FLAG_FILTER_TYPE_ALERTING);
    }

    @Test
    public void testEnsureFilters_newServiceWithMetadata_disabledTypes() {
        ServiceInfo si = new ServiceInfo();
        si.packageName = "new";
        si.name = "comp";
        si.metaData = new Bundle();
        si.metaData.putString(NotificationListenerService.META_DATA_DISABLED_FILTER_TYPES, "1,2");

        mListeners.ensureFilters(si, 0);

        assertThat(mListeners.getNotificationListenerFilter(
                Pair.create(si.getComponentName(), 0)).getTypes())
                .isEqualTo(FLAG_FILTER_TYPE_SILENT | FLAG_FILTER_TYPE_ONGOING);
    }

    @Test
    public void testEnsureFilters_newServiceWithMetadata_metaDataDisagrees() {
        ServiceInfo si = new ServiceInfo();
        si.packageName = "new";
        si.name = "comp";
        si.metaData = new Bundle();
        si.metaData.putString(NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES, "1,2");
        si.metaData.putInt(NotificationListenerService.META_DATA_DISABLED_FILTER_TYPES, 1);

        mListeners.ensureFilters(si, 0);

        assertThat(mListeners.getNotificationListenerFilter(
                Pair.create(si.getComponentName(), 0)).getTypes())
                .isEqualTo(FLAG_FILTER_TYPE_ALERTING);
    }

    @Test
    public void testEnsureFilters_newServiceWithEmptyMetadata() {
        ServiceInfo si = new ServiceInfo();