Loading res/values/arrays.xml +17 −0 Original line number Diff line number Diff line Loading @@ -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> res/values/strings.xml +5 −0 Original line number Diff line number Diff line Loading @@ -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> res/xml/notification_access_permission_details.xml +17 −0 Original line number Diff line number Diff line Loading @@ -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 src/com/android/settings/applications/specialaccess/notificationaccess/NotificationAccessDetails.java +9 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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) { Loading @@ -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 Loading src/com/android/settings/applications/specialaccess/notificationaccess/TypeFilterPreferenceController.java 0 → 100644 +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
res/values/arrays.xml +17 −0 Original line number Diff line number Diff line Loading @@ -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>
res/values/strings.xml +5 −0 Original line number Diff line number Diff line Loading @@ -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>
res/xml/notification_access_permission_details.xml +17 −0 Original line number Diff line number Diff line Loading @@ -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
src/com/android/settings/applications/specialaccess/notificationaccess/NotificationAccessDetails.java +9 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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) { Loading @@ -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 Loading
src/com/android/settings/applications/specialaccess/notificationaccess/TypeFilterPreferenceController.java 0 → 100644 +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