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

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

Allow notification filtering per listener.

Test: atest
Bug: 173052211
Change-Id: I54c740e9755f18339c59aad4f1f5aecd8c734892
parent 0fd2a200
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -1532,4 +1532,21 @@
        <item>8</item>
        <item>12</item>
    </string-array>

    <!-- Array of titles list for notification listener notification types. [DO NOT TRANSLATE] -->
    <string-array name="notif_types_titles" translatable="false">
        <item>@string/notif_type_ongoing</item>
        <item>@string/notif_type_conversation</item>
        <item>@string/notif_type_alerting</item>
        <item>@string/notif_type_silent</item>
    </string-array>

    <!-- Values of list for notification listener notification types. Values need to match
    android.service.notification.NotificationListenerService. [DO NOT TRANSLATE] -->
    <string-array name="notif_types_values" translatable="false">
        <item>8</item>
        <item>1</item>
        <item>2</item>
        <item>4</item>
    </string-array>
</resources>
+5 −0
Original line number Diff line number Diff line
@@ -8756,6 +8756,11 @@
    </string>
    <string name="notification_listener_disable_warning_confirm">Turn off</string>
    <string name="notification_listener_disable_warning_cancel">Cancel</string>
    <string name="notification_listener_type_title">Allowed notification types</string>
    <string name="notif_type_ongoing">Important ongoing notifications</string>
    <string name="notif_type_conversation">Conversation notifications</string>
    <string name="notif_type_alerting">Alerting notifications</string>
    <string name="notif_type_silent">Silent notifications</string>
    <!-- Title for managing VR (virtual reality) helper services. [CHAR LIMIT=50] -->
    <string name="vr_listeners_title">VR helper services</string>
+17 −0
Original line number Diff line number Diff line
@@ -31,4 +31,21 @@
        android:title="@string/notification_access_detail_switch"
        settings:controller="com.android.settings.applications.specialaccess.notificationaccess.ApprovalPreferenceController"/>

    <MultiSelectListPreference
        android:key="notification_type_filter"
        android:title="@string/notification_listener_type_title"
        android:entries="@array/notif_types_titles"
        android:entryValues="@array/notif_types_values"
        android:summary="%s"
        android:persistent="false"
        style="@style/SettingsMultiSelectListPreference"
        settings:controller="com.android.settings.applications.specialaccess.notificationaccess.TypeFilterPreferenceController"/>/>

    <PreferenceCategory
        android:key="advanced"
        android:order="50"
        settings:initialExpandedChildrenCount="0">


    </PreferenceCategory>
</PreferenceScreen>
 No newline at end of file
+9 −2
Original line number Diff line number Diff line
@@ -42,11 +42,10 @@ import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.applications.manageapplications.ManageApplications;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.notification.NotificationBackend;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.applications.ApplicationsState;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@@ -91,6 +90,10 @@ public class NotificationAccessDetails extends DashboardFragment {
                .setPackageInfo(mPackageInfo)
                .setPm(context.getPackageManager())
                .setServiceName(mServiceName);
        use(TypeFilterPreferenceController.class)
                .setNm(new NotificationBackend())
                .setCn(mComponentName)
                .setUserId(mUserId);
    }

    @Override
@@ -172,6 +175,8 @@ public class NotificationAccessDetails extends DashboardFragment {
        ApprovalPreferenceController controller = use(ApprovalPreferenceController.class);
        controller.disable(cn);
        controller.updateState(screen.findPreference(controller.getPreferenceKey()));
        TypeFilterPreferenceController dependent1 = use(TypeFilterPreferenceController.class);
        dependent1.updateState(screen.findPreference(dependent1.getPreferenceKey()));
    }

    protected void enable(ComponentName cn) {
@@ -179,6 +184,8 @@ public class NotificationAccessDetails extends DashboardFragment {
        ApprovalPreferenceController controller = use(ApprovalPreferenceController.class);
        controller.enable(cn);
        controller.updateState(screen.findPreference(controller.getPreferenceKey()));
        TypeFilterPreferenceController dependent1 = use(TypeFilterPreferenceController.class);
        dependent1.updateState(screen.findPreference(dependent1.getPreferenceKey()));
    }

    // To save binder calls, load this in the fragment rather than each preference controller
+144 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.settings.applications.specialaccess.notificationaccess;

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 android.content.ComponentName;
import android.content.Context;
import android.service.notification.NotificationListenerFilter;

import androidx.preference.MultiSelectListPreference;
import androidx.preference.Preference;

import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.notification.NotificationBackend;

import java.util.HashSet;
import java.util.Set;

public class TypeFilterPreferenceController extends BasePreferenceController implements
        PreferenceControllerMixin, Preference.OnPreferenceChangeListener {

    private static final String TAG = "TypeFilterPrefCntlr";

    private ComponentName mCn;
    private int mUserId;
    private NotificationBackend mNm;
    private NotificationListenerFilter mNlf;

    public TypeFilterPreferenceController(Context context, String key) {
        super(context, key);
    }

    public TypeFilterPreferenceController setCn(ComponentName cn) {
        mCn = cn;
        return this;
    }

    public TypeFilterPreferenceController setUserId(int userId) {
        mUserId = userId;
        return this;
    }

    public TypeFilterPreferenceController setNm(NotificationBackend nm) {
        mNm = nm;
        return this;
    }

    @Override
    public int getAvailabilityStatus() {
        if (mNm.isNotificationListenerAccessGranted(mCn)) {
            return AVAILABLE;
        } else {
            return DISABLED_DEPENDENT_SETTING;
        }
    }

    @Override
    public void updateState(Preference pref) {
        mNlf = mNm.getListenerFilter(mCn, mUserId);
        Set<String> values = new HashSet<>();
        Set<String> entries = new HashSet<>();

        if (hasFlag(mNlf.getTypes(), FLAG_FILTER_TYPE_ONGOING)) {
            values.add(String.valueOf(FLAG_FILTER_TYPE_ONGOING));
            entries.add(mContext.getString(R.string.notif_type_ongoing));
        }
        if (hasFlag(mNlf.getTypes(), FLAG_FILTER_TYPE_CONVERSATIONS)) {
            values.add(String.valueOf(FLAG_FILTER_TYPE_CONVERSATIONS));
            entries.add(mContext.getString(R.string.notif_type_conversation));
        }
        if (hasFlag(mNlf.getTypes(), FLAG_FILTER_TYPE_ALERTING)) {
            values.add(String.valueOf(FLAG_FILTER_TYPE_ALERTING));
            entries.add(mContext.getString(R.string.notif_type_alerting));
        }
        if (hasFlag(mNlf.getTypes(), FLAG_FILTER_TYPE_SILENT)) {
            values.add(String.valueOf(FLAG_FILTER_TYPE_SILENT));
            entries.add(mContext.getString(R.string.notif_type_silent));
        }

        final MultiSelectListPreference preference = (MultiSelectListPreference) pref;
        preference.setValues(values);
        super.updateState(preference);
        pref.setEnabled(getAvailabilityStatus() == AVAILABLE);
    }

    private boolean hasFlag(int value, int flag) {
        return (value & flag) != 0;
    }

    public CharSequence getSummary() {
        Set<String> entries = new HashSet<>();
        if (hasFlag(mNlf.getTypes(), FLAG_FILTER_TYPE_ONGOING)) {
            entries.add(mContext.getString(R.string.notif_type_ongoing));
        }
        if (hasFlag(mNlf.getTypes(), FLAG_FILTER_TYPE_CONVERSATIONS)) {
            entries.add(mContext.getString(R.string.notif_type_conversation));
        }
        if (hasFlag(mNlf.getTypes(), FLAG_FILTER_TYPE_ALERTING)) {
            entries.add(mContext.getString(R.string.notif_type_alerting));
        }
        if (hasFlag(mNlf.getTypes(), FLAG_FILTER_TYPE_SILENT)) {
            entries.add(mContext.getString(R.string.notif_type_silent));
        }
        return String.join(System.lineSeparator(), entries);
    }

    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        // retrieve latest in case the package filter has changed
        mNlf = mNm.getListenerFilter(mCn, mUserId);

        Set<String> set = (Set<String>) newValue;

        int newFilter = 0;
        for (String filterType : set) {
            newFilter |= Integer.parseInt(filterType);
        }
        mNlf.setTypes(newFilter);
        preference.setSummary(getSummary());
        mNm.setListenerFilter(mCn, mUserId, mNlf);
        return true;
    }

}
 No newline at end of file
Loading