DND Bypassing Apps redesign
- Add link in DND Conversations Page to the overall conversations list Settings page - Add custom_rule xml pages for custom schedule rule settings for messages and calls (so the UI is the same as before the message/calls redesign) - Change app exceptions to display apps with subtext indicating which notitfication channels are allowed to bypass dnd (previously, would display each channel individually) - Add individual AppBypassDnd channel pages where users can decide which channels will bypass DND for an app on a single page (AppChannelsBypassingDndSettings) - Only remove dnd bypassing apps preferences from the preference list if the list changed, else just update the preference itself to avoid the list from flashing Test: make RunSettingsRoboTests7 Bug: 151845457 Change-Id: If12d8921e1405aefb1066acc2ef5c55d216fe47a
This commit is contained in:
@@ -6908,7 +6908,8 @@
|
|||||||
<!-- Summary for add user action, when it's disabled [CHAR LIMIT=100] -->
|
<!-- Summary for add user action, when it's disabled [CHAR LIMIT=100] -->
|
||||||
<string name="user_add_max_count">You can add up to <xliff:g id="user_count">%1$d</xliff:g> users</string>
|
<string name="user_add_max_count">You can add up to <xliff:g id="user_count">%1$d</xliff:g> users</string>
|
||||||
|
|
||||||
<!-- Message to secondary users that only owner can manage users [CHAR LIMIT=none] -->
|
|
||||||
|
<!-- Message to secondary users that only owner can manage users [CHAR LIMIT=none] -->
|
||||||
<string name="user_cannot_manage_message" product="tablet">Only the tablet\u2019s owner can manage users.</string>
|
<string name="user_cannot_manage_message" product="tablet">Only the tablet\u2019s owner can manage users.</string>
|
||||||
<!-- Message to secondary users that only owner can manage users [CHAR LIMIT=none] -->
|
<!-- Message to secondary users that only owner can manage users [CHAR LIMIT=none] -->
|
||||||
<string name="user_cannot_manage_message" product="default">Only the phone\u2019s owner can manage users.</string>
|
<string name="user_cannot_manage_message" product="default">Only the phone\u2019s owner can manage users.</string>
|
||||||
@@ -8973,8 +8974,22 @@
|
|||||||
<string name="zen_mode_bypassing_apps">Allow apps to override</string>
|
<string name="zen_mode_bypassing_apps">Allow apps to override</string>
|
||||||
<!-- [CHAR LIMIT=100] Zen mode settings: Allow apps to bypass DND header -->
|
<!-- [CHAR LIMIT=100] Zen mode settings: Allow apps to bypass DND header -->
|
||||||
<string name="zen_mode_bypassing_apps_header">Apps that can interrupt</string>
|
<string name="zen_mode_bypassing_apps_header">Apps that can interrupt</string>
|
||||||
|
<!-- [CHAR LIMIT=100] Zen mode settings: Add apps to bypass DND header -->
|
||||||
|
<string name="zen_mode_bypassing_apps_add_header">Select more apps</string>
|
||||||
|
<!-- [CHAR LIMIT=120] Zen mode settings: No apps are bypassing DND -->
|
||||||
|
<string name="zen_mode_bypassing_apps_none">No apps selected</string>
|
||||||
<!-- [CHAR LIMIT=120] Zen mode settings: No apps are bypassing DND -->
|
<!-- [CHAR LIMIT=120] Zen mode settings: No apps are bypassing DND -->
|
||||||
<string name="zen_mode_bypassing_apps_subtext_none">No apps can interrupt</string>
|
<string name="zen_mode_bypassing_apps_subtext_none">No apps can interrupt</string>
|
||||||
|
<!-- [CHAR LIMIT=120] Zen mode settings: Preference to add apps that are allowed to bypass DND -->
|
||||||
|
<string name="zen_mode_bypassing_apps_add">Add apps</string>
|
||||||
|
<!-- [CHAR LIMIT=120] Zen mode settings: Summary indicating all notification channels can
|
||||||
|
bypass DND for this app -->
|
||||||
|
<string name="zen_mode_bypassing_apps_summary_all">All notifications</string>
|
||||||
|
<!-- [CHAR LIMIT=120] Zen mode settings: Summary indicating all notification channels can
|
||||||
|
bypass DND for this app -->
|
||||||
|
<string name="zen_mode_bypassing_apps_summary_some">Some notifications</string>
|
||||||
|
<!-- [CHAR LIMIT=NONE] Zen mode settings: Footer for DND bypassing apps settings -->
|
||||||
|
<string name="zen_mode_bypassing_apps_footer">Selected people can still reach you, even if you don\u2019t allow apps to interrupt</string>
|
||||||
<!-- [CHAR LIMIT=120] Zen mode settings: Allow apps to bypass DND -->
|
<!-- [CHAR LIMIT=120] Zen mode settings: Allow apps to bypass DND -->
|
||||||
<plurals name="zen_mode_bypassing_apps_subtext">
|
<plurals name="zen_mode_bypassing_apps_subtext">
|
||||||
<item quantity="one"><xliff:g id="app_name" example="Nest">%s</xliff:g> can interrupt</item>
|
<item quantity="one"><xliff:g id="app_name" example="Nest">%s</xliff:g> can interrupt</item>
|
||||||
@@ -8989,6 +9004,11 @@
|
|||||||
<string name="zen_mode_bypassing_apps_all_summary">All notifications</string>
|
<string name="zen_mode_bypassing_apps_all_summary">All notifications</string>
|
||||||
<!-- [CHAR LIMIT=100] Zen mode settings: App that can bypass DND's secondary text describing which notification channels from the app can bypass DND-->
|
<!-- [CHAR LIMIT=100] Zen mode settings: App that can bypass DND's secondary text describing which notification channels from the app can bypass DND-->
|
||||||
<string name="zen_mode_bypassing_apps_some_summary">Some notifications</string>
|
<string name="zen_mode_bypassing_apps_some_summary">Some notifications</string>
|
||||||
|
<!-- [CHAR LIMIT=100] Zen mode settings: Allow notifications from an app to bypass DND header -->
|
||||||
|
<string name="zen_mode_bypassing_app_channels_header">Notifications that can interrupt</string>
|
||||||
|
<!-- [CHAR LIMIT=100] Zen mode settings: Allow all notifications from an app to bypass DND
|
||||||
|
toggle title -->
|
||||||
|
<string name="zen_mode_bypassing_app_channels_toggle_all">Allow all notifications</string>
|
||||||
|
|
||||||
<!-- [CHAR LIMIT=120] Zen mode settings: Summary for sound interruption settings -->
|
<!-- [CHAR LIMIT=120] Zen mode settings: Summary for sound interruption settings -->
|
||||||
<plurals name="zen_mode_other_sounds_summary">
|
<plurals name="zen_mode_other_sounds_summary">
|
||||||
@@ -9022,9 +9042,9 @@
|
|||||||
<!-- [CHAR LIMIT=50] Zen mode settings: Repeat callers (ie: repeat callers are allowed to bypass dnd) -->
|
<!-- [CHAR LIMIT=50] Zen mode settings: Repeat callers (ie: repeat callers are allowed to bypass dnd) -->
|
||||||
<string name="zen_mode_repeat_callers_list">repeat callers</string>
|
<string name="zen_mode_repeat_callers_list">repeat callers</string>
|
||||||
<!-- [CHAR LIMIT=50] Zen mode settings: calls summary -->
|
<!-- [CHAR LIMIT=50] Zen mode settings: calls summary -->
|
||||||
<string name="zen_mode_calls_summary_one">Allow from <xliff:g id="caller type" example="contacts">%1$s</xliff:g></string>
|
<string name="zen_mode_calls_summary_one"><xliff:g id="caller type" example="contacts">%1$s</xliff:g></string>
|
||||||
<!-- [CHAR LIMIT=50] Zen mode settings: calls summary -->
|
<!-- [CHAR LIMIT=50] Zen mode settings: calls summary -->
|
||||||
<string name="zen_mode_calls_summary_two">Allow from <xliff:g id="caller type" example="starred contacts">%1$s</xliff:g> and <xliff:g id="callert tpye" example="repeat callers">%2$s</xliff:g></string>
|
<string name="zen_mode_calls_summary_two"><xliff:g id="caller type" example="starred contacts">%1$s</xliff:g> and <xliff:g id="caller type" example="repeat callers">%2$s</xliff:g></string>
|
||||||
<!-- [CHAR LIMIT=200] Zen mode settings: Repeat callers option summary -->
|
<!-- [CHAR LIMIT=200] Zen mode settings: Repeat callers option summary -->
|
||||||
<string name="zen_mode_repeat_callers_summary">If the same person calls a second time within a <xliff:g id="minutes">%d</xliff:g> minute period</string>
|
<string name="zen_mode_repeat_callers_summary">If the same person calls a second time within a <xliff:g id="minutes">%d</xliff:g> minute period</string>
|
||||||
|
|
||||||
|
29
res/xml/app_channels_bypassing_dnd_settings.xml
Normal file
29
res/xml/app_channels_bypassing_dnd_settings.xml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright (C) 2020 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:title="@string/zen_mode_settings_title">
|
||||||
|
<com.android.settingslib.widget.LayoutPreference
|
||||||
|
android:key="pref_app_header"
|
||||||
|
android:layout="@layout/settings_entity_header" />
|
||||||
|
|
||||||
|
<PreferenceCategory
|
||||||
|
android:key="zen_mode_bypassing_app_channels_list"
|
||||||
|
android:title="@string/zen_mode_bypassing_app_channels_header">
|
||||||
|
<!-- add app channel toggles here -->
|
||||||
|
</PreferenceCategory>
|
||||||
|
</PreferenceScreen>
|
@@ -14,10 +14,11 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
<PreferenceScreen
|
||||||
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:key="conversation_list"
|
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||||
android:title="zen_mode_conversations_title">
|
android:key="conversation_list"
|
||||||
|
android:title="@string/zen_mode_conversations_title">
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
android:key="important_conversations"
|
android:key="important_conversations"
|
||||||
|
@@ -17,4 +17,21 @@
|
|||||||
|
|
||||||
<PreferenceScreen
|
<PreferenceScreen
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:title="@string/zen_mode_bypassing_apps_title" />
|
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:title="@string/zen_mode_bypassing_apps_title">
|
||||||
|
|
||||||
|
<PreferenceCategory
|
||||||
|
android:key="zen_mode_bypassing_apps_list"
|
||||||
|
android:title="@string/zen_mode_bypassing_apps_header">
|
||||||
|
<!-- apps that have notifications that can bypass DND are added here -->
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="zen_mode_bypassing_apps_add"
|
||||||
|
android:title="@string/zen_mode_bypassing_apps_add"
|
||||||
|
android:icon="@drawable/ic_add_24dp"
|
||||||
|
settings:allowDividerAbove="true" />
|
||||||
|
|
||||||
|
<com.android.settingslib.widget.FooterPreference
|
||||||
|
android:title="@string/zen_mode_bypassing_apps_footer" />
|
||||||
|
</PreferenceScreen>
|
||||||
|
45
res/xml/zen_mode_custom_rule_calls_settings.xml
Normal file
45
res/xml/zen_mode_custom_rule_calls_settings.xml
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright (C) 2020 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<PreferenceScreen
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:key="zen_mode_custom_rule_calls_settings_page"
|
||||||
|
android:title="@string/zen_mode_calls_title" >
|
||||||
|
|
||||||
|
<PreferenceCategory
|
||||||
|
android:key="zen_mode_settings_category_calls"
|
||||||
|
android:title="@string/zen_mode_settings_category">
|
||||||
|
<!-- Calls -->
|
||||||
|
<ListPreference
|
||||||
|
android:key="zen_mode_calls"
|
||||||
|
android:title="@string/zen_mode_calls"
|
||||||
|
android:entries="@array/zen_mode_contacts_calls_entries"
|
||||||
|
android:entryValues="@array/zen_mode_contacts_values"/>
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="zen_mode_starred_contacts_callers"
|
||||||
|
android:title="@string/zen_mode_starred_contacts_title"/>
|
||||||
|
|
||||||
|
<!-- Repeat callers -->
|
||||||
|
<SwitchPreference
|
||||||
|
android:key="zen_mode_repeat_callers"
|
||||||
|
android:title="@string/zen_mode_repeat_callers_title" />
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
<com.android.settingslib.widget.FooterPreference/>
|
||||||
|
|
||||||
|
</PreferenceScreen>
|
40
res/xml/zen_mode_custom_rule_messages_settings.xml
Normal file
40
res/xml/zen_mode_custom_rule_messages_settings.xml
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright (C) 2020 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<PreferenceScreen
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:key="zen_mode_custom_rule_messages_settings_page"
|
||||||
|
android:title="@string/zen_mode_messages_title" >
|
||||||
|
|
||||||
|
<PreferenceCategory
|
||||||
|
android:title="@string/zen_mode_settings_category"
|
||||||
|
android:key="zen_mode_settings_category_messages">
|
||||||
|
<!-- Messages -->
|
||||||
|
<ListPreference
|
||||||
|
android:key="zen_mode_messages"
|
||||||
|
android:title="@string/zen_mode_messages"
|
||||||
|
android:entries="@array/zen_mode_contacts_messages_entries"
|
||||||
|
android:entryValues="@array/zen_mode_contacts_values"/>
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="zen_mode_starred_contacts_messages"
|
||||||
|
android:title="@string/zen_mode_starred_contacts_title"/>
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
<com.android.settingslib.widget.FooterPreference/>
|
||||||
|
|
||||||
|
</PreferenceScreen>
|
@@ -0,0 +1,227 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.notification.app;
|
||||||
|
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_NONE;
|
||||||
|
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationChannelGroup;
|
||||||
|
import android.app.settings.SettingsEnums;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.provider.Settings;
|
||||||
|
|
||||||
|
import androidx.core.text.BidiFormatter;
|
||||||
|
import androidx.lifecycle.LifecycleObserver;
|
||||||
|
import androidx.preference.Preference;
|
||||||
|
import androidx.preference.PreferenceCategory;
|
||||||
|
import androidx.preference.PreferenceScreen;
|
||||||
|
import androidx.preference.SwitchPreference;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.applications.AppInfoBase;
|
||||||
|
import com.android.settings.core.PreferenceControllerMixin;
|
||||||
|
import com.android.settings.core.SubSettingLauncher;
|
||||||
|
import com.android.settings.notification.NotificationBackend;
|
||||||
|
import com.android.settings.widget.MasterSwitchPreference;
|
||||||
|
import com.android.settingslib.RestrictedSwitchPreference;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populates the PreferenceCategory with notification channels associated with the given app.
|
||||||
|
* Users can allow/disallow notification channels from bypassing DND on a single settings
|
||||||
|
* page.
|
||||||
|
*/
|
||||||
|
public class AppChannelsBypassingDndPreferenceController extends NotificationPreferenceController
|
||||||
|
implements PreferenceControllerMixin, LifecycleObserver {
|
||||||
|
|
||||||
|
private static final String KEY = "zen_mode_bypassing_app_channels_list";
|
||||||
|
private static final String ARG_FROM_SETTINGS = "fromSettings";
|
||||||
|
|
||||||
|
private RestrictedSwitchPreference mAllNotificationsToggle;
|
||||||
|
private PreferenceCategory mPreferenceCategory;
|
||||||
|
private final List<NotificationChannel> mChannels = new ArrayList<>();
|
||||||
|
|
||||||
|
public AppChannelsBypassingDndPreferenceController(
|
||||||
|
Context context,
|
||||||
|
NotificationBackend backend) {
|
||||||
|
super(context, backend);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void displayPreference(PreferenceScreen screen) {
|
||||||
|
mPreferenceCategory = screen.findPreference(KEY);
|
||||||
|
|
||||||
|
mAllNotificationsToggle = new RestrictedSwitchPreference(mPreferenceCategory.getContext());
|
||||||
|
mAllNotificationsToggle.setTitle(R.string.zen_mode_bypassing_app_channels_toggle_all);
|
||||||
|
mAllNotificationsToggle.setDisabledByAdmin(mAdmin);
|
||||||
|
mAllNotificationsToggle.setEnabled(
|
||||||
|
(mAdmin == null || !mAllNotificationsToggle.isDisabledByAdmin()));
|
||||||
|
mAllNotificationsToggle.setOnPreferenceClickListener(
|
||||||
|
new Preference.OnPreferenceClickListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceClick(Preference pref) {
|
||||||
|
SwitchPreference preference = (SwitchPreference) pref;
|
||||||
|
final boolean bypassDnd = preference.isChecked();
|
||||||
|
for (NotificationChannel channel : mChannels) {
|
||||||
|
if (showNotification(channel) && isChannelConfigurable(channel)) {
|
||||||
|
channel.setBypassDnd(bypassDnd);
|
||||||
|
channel.lockFields(NotificationChannel.USER_LOCKED_PRIORITY);
|
||||||
|
mBackend.updateChannel(mAppRow.pkg, mAppRow.uid, channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// the 0th index is the mAllNotificationsToggle which allows users to
|
||||||
|
// toggle all notifications from this app to bypass DND
|
||||||
|
for (int i = 1; i < mPreferenceCategory.getPreferenceCount(); i++) {
|
||||||
|
MasterSwitchPreference childPreference =
|
||||||
|
(MasterSwitchPreference) mPreferenceCategory.getPreference(i);
|
||||||
|
childPreference.setChecked(showNotificationInDnd(mChannels.get(i - 1)));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
loadAppChannels();
|
||||||
|
super.displayPreference(screen);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPreferenceKey() {
|
||||||
|
return KEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable() {
|
||||||
|
return mAppRow != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateState(Preference preference) {
|
||||||
|
if (mAppRow != null) {
|
||||||
|
loadAppChannels();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadAppChannels() {
|
||||||
|
// Load channel settings
|
||||||
|
new AsyncTask<Void, Void, Void>() {
|
||||||
|
@Override
|
||||||
|
protected Void doInBackground(Void... unused) {
|
||||||
|
List<NotificationChannelGroup> mChannelGroupList = mBackend.getGroups(mAppRow.pkg,
|
||||||
|
mAppRow.uid).getList();
|
||||||
|
mChannels.clear();
|
||||||
|
for (NotificationChannelGroup channelGroup : mChannelGroupList) {
|
||||||
|
for (NotificationChannel channel : channelGroup.getChannels()) {
|
||||||
|
if (!isConversation(channel)) {
|
||||||
|
mChannels.add(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Collections.sort(mChannels, CHANNEL_COMPARATOR);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Void unused) {
|
||||||
|
if (mContext == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
populateList();
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void populateList() {
|
||||||
|
if (mPreferenceCategory == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mPreferenceCategory.removeAll();
|
||||||
|
mPreferenceCategory.addPreference(mAllNotificationsToggle);
|
||||||
|
for (NotificationChannel channel : mChannels) {
|
||||||
|
MasterSwitchPreference channelPreference = new MasterSwitchPreference(mContext);
|
||||||
|
channelPreference.setDisabledByAdmin(mAdmin);
|
||||||
|
channelPreference.setSwitchEnabled(
|
||||||
|
(mAdmin == null || !channelPreference.isDisabledByAdmin())
|
||||||
|
&& isChannelConfigurable(channel)
|
||||||
|
&& showNotification(channel));
|
||||||
|
channelPreference.setTitle(BidiFormatter.getInstance().unicodeWrap(channel.getName()));
|
||||||
|
channelPreference.setChecked(showNotificationInDnd(channel));
|
||||||
|
channelPreference.setOnPreferenceChangeListener(
|
||||||
|
new Preference.OnPreferenceChangeListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceChange(Preference pref, Object val) {
|
||||||
|
boolean switchOn = (Boolean) val;
|
||||||
|
channel.setBypassDnd(switchOn);
|
||||||
|
channel.lockFields(NotificationChannel.USER_LOCKED_PRIORITY);
|
||||||
|
mBackend.updateChannel(mAppRow.pkg, mAppRow.uid, channel);
|
||||||
|
mAllNotificationsToggle.setChecked(areAllChannelsBypassing());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Bundle channelArgs = new Bundle();
|
||||||
|
channelArgs.putInt(AppInfoBase.ARG_PACKAGE_UID, mAppRow.uid);
|
||||||
|
channelArgs.putString(AppInfoBase.ARG_PACKAGE_NAME, mAppRow.pkg);
|
||||||
|
channelArgs.putString(Settings.EXTRA_CHANNEL_ID, channel.getId());
|
||||||
|
channelArgs.putBoolean(ARG_FROM_SETTINGS, true);
|
||||||
|
channelPreference.setIntent(new SubSettingLauncher(mContext)
|
||||||
|
.setDestination(ChannelNotificationSettings.class.getName())
|
||||||
|
.setArguments(channelArgs)
|
||||||
|
.setTitleRes(com.android.settings.R.string.notification_channel_title)
|
||||||
|
.setSourceMetricsCategory(SettingsEnums.DND_APPS_BYPASSING)
|
||||||
|
.toIntent());
|
||||||
|
mPreferenceCategory.addPreference(channelPreference);
|
||||||
|
}
|
||||||
|
mAllNotificationsToggle.setChecked(areAllChannelsBypassing());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean areAllChannelsBypassing() {
|
||||||
|
boolean allChannelsBypassing = true;
|
||||||
|
for (NotificationChannel channel : mChannels) {
|
||||||
|
if (showNotification(channel)) {
|
||||||
|
allChannelsBypassing &= showNotificationInDnd(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allChannelsBypassing;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether notifications from this channel would show if DND were on.
|
||||||
|
*/
|
||||||
|
private boolean showNotificationInDnd(NotificationChannel channel) {
|
||||||
|
return channel.canBypassDnd() && showNotification(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether notifications from this channel would show if DND weren't on.
|
||||||
|
*/
|
||||||
|
private boolean showNotification(NotificationChannel channel) {
|
||||||
|
return channel.getImportance() != IMPORTANCE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this notification channel is representing a conversation.
|
||||||
|
*/
|
||||||
|
private boolean isConversation(NotificationChannel channel) {
|
||||||
|
return channel.getConversationId() != null && !channel.isDemoted();
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.notification.app;
|
||||||
|
|
||||||
|
import android.app.settings.SettingsEnums;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.notification.NotificationBackend;
|
||||||
|
import com.android.settingslib.core.AbstractPreferenceController;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Per-app Settings page that shows a list of notification channels that a user can toggle for
|
||||||
|
* the channel to bypass DND.
|
||||||
|
*
|
||||||
|
* This can be found at:
|
||||||
|
* Settings > Sound > Do Not Disturb > Apps > (Choose app)
|
||||||
|
*/
|
||||||
|
public class AppChannelsBypassingDndSettings extends NotificationSettings {
|
||||||
|
private static final String TAG = "AppChannelsBypassingDndSettings";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMetricsCategory() {
|
||||||
|
return SettingsEnums.DND_APPS_BYPASSING;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
if (mUid < 0 || TextUtils.isEmpty(mPkg) || mPkgInfo == null) {
|
||||||
|
Log.w(TAG, "Missing package or uid or packageinfo");
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (NotificationPreferenceController controller : mControllers) {
|
||||||
|
controller.onResume(mAppRow, null, null, null, null, mSuspendedAppsAdmin);
|
||||||
|
controller.displayPreference(getPreferenceScreen());
|
||||||
|
}
|
||||||
|
updatePreferenceStates();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getLogTag() {
|
||||||
|
return TAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getPreferenceScreenResId() {
|
||||||
|
return R.xml.app_channels_bypassing_dnd_settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
|
||||||
|
mControllers = new ArrayList<>();
|
||||||
|
mControllers.add(new HeaderPreferenceController(context, this));
|
||||||
|
mControllers.add(new AppChannelsBypassingDndPreferenceController(context,
|
||||||
|
new NotificationBackend()));
|
||||||
|
return new ArrayList<>(mControllers);
|
||||||
|
}
|
||||||
|
}
|
@@ -33,6 +33,11 @@ import android.os.Bundle;
|
|||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import androidx.preference.Preference;
|
||||||
|
import androidx.preference.PreferenceCategory;
|
||||||
|
import androidx.preference.PreferenceGroup;
|
||||||
|
import androidx.preference.SwitchPreference;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.Utils;
|
import com.android.settings.Utils;
|
||||||
import com.android.settings.applications.AppInfoBase;
|
import com.android.settings.applications.AppInfoBase;
|
||||||
@@ -43,14 +48,8 @@ import com.android.settingslib.RestrictedSwitchPreference;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import androidx.preference.Preference;
|
|
||||||
import androidx.preference.PreferenceCategory;
|
|
||||||
import androidx.preference.PreferenceGroup;
|
|
||||||
import androidx.preference.SwitchPreference;
|
|
||||||
|
|
||||||
public class ChannelListPreferenceController extends NotificationPreferenceController {
|
public class ChannelListPreferenceController extends NotificationPreferenceController {
|
||||||
|
|
||||||
private static final String KEY = "channels";
|
private static final String KEY = "channels";
|
||||||
@@ -94,7 +93,7 @@ public class ChannelListPreferenceController extends NotificationPreferenceContr
|
|||||||
@Override
|
@Override
|
||||||
protected Void doInBackground(Void... unused) {
|
protected Void doInBackground(Void... unused) {
|
||||||
mChannelGroupList = mBackend.getGroups(mAppRow.pkg, mAppRow.uid).getList();
|
mChannelGroupList = mBackend.getGroups(mAppRow.pkg, mAppRow.uid).getList();
|
||||||
Collections.sort(mChannelGroupList, mChannelGroupComparator);
|
Collections.sort(mChannelGroupList, CHANNEL_GROUP_COMPARATOR);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +141,7 @@ public class ChannelListPreferenceController extends NotificationPreferenceContr
|
|||||||
}
|
}
|
||||||
if (!group.isBlocked()) {
|
if (!group.isBlocked()) {
|
||||||
final List<NotificationChannel> channels = group.getChannels();
|
final List<NotificationChannel> channels = group.getChannels();
|
||||||
Collections.sort(channels, mChannelComparator);
|
Collections.sort(channels, CHANNEL_COMPARATOR);
|
||||||
int N = channels.size();
|
int N = channels.size();
|
||||||
for (int i = 0; i < N; i++) {
|
for (int i = 0; i < N; i++) {
|
||||||
final NotificationChannel channel = channels.get(i);
|
final NotificationChannel channel = channels.get(i);
|
||||||
@@ -274,7 +273,7 @@ public class ChannelListPreferenceController extends NotificationPreferenceContr
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
final List<NotificationChannel> channels = group.getChannels();
|
final List<NotificationChannel> channels = group.getChannels();
|
||||||
Collections.sort(channels, mChannelComparator);
|
Collections.sort(channels, CHANNEL_COMPARATOR);
|
||||||
int N = channels.size();
|
int N = channels.size();
|
||||||
for (int i = 0; i < N; i++) {
|
for (int i = 0; i < N; i++) {
|
||||||
final NotificationChannel channel = channels.get(i);
|
final NotificationChannel channel = channels.get(i);
|
||||||
@@ -283,33 +282,4 @@ public class ChannelListPreferenceController extends NotificationPreferenceContr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Comparator<NotificationChannelGroup> mChannelGroupComparator =
|
|
||||||
new Comparator<NotificationChannelGroup>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compare(NotificationChannelGroup left, NotificationChannelGroup right) {
|
|
||||||
// Non-grouped channels (in placeholder group with a null id) come last
|
|
||||||
if (left.getId() == null && right.getId() != null) {
|
|
||||||
return 1;
|
|
||||||
} else if (right.getId() == null && left.getId() != null) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return left.getId().compareTo(right.getId());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
protected Comparator<NotificationChannel> mChannelComparator =
|
|
||||||
(left, right) -> {
|
|
||||||
if (left.isDeleted() != right.isDeleted()) {
|
|
||||||
return Boolean.compare(left.isDeleted(), right.isDeleted());
|
|
||||||
} else if (left.getId().equals(NotificationChannel.DEFAULT_CHANNEL_ID)) {
|
|
||||||
// Uncategorized/miscellaneous legacy channel goes last
|
|
||||||
return 1;
|
|
||||||
} else if (right.getId().equals(NotificationChannel.DEFAULT_CHANNEL_ID)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return left.getId().compareTo(right.getId());
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
@@ -35,6 +35,7 @@ import com.android.settings.notification.NotificationBackend;
|
|||||||
import com.android.settingslib.RestrictedLockUtils;
|
import com.android.settingslib.RestrictedLockUtils;
|
||||||
import com.android.settingslib.core.AbstractPreferenceController;
|
import com.android.settingslib.core.AbstractPreferenceController;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -172,4 +173,31 @@ public abstract class NotificationPreferenceController extends AbstractPreferenc
|
|||||||
}
|
}
|
||||||
return Objects.equals(NotificationChannel.DEFAULT_CHANNEL_ID, mChannel.getId());
|
return Objects.equals(NotificationChannel.DEFAULT_CHANNEL_ID, mChannel.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final Comparator<NotificationChannelGroup> CHANNEL_GROUP_COMPARATOR =
|
||||||
|
new Comparator<NotificationChannelGroup>() {
|
||||||
|
@Override
|
||||||
|
public int compare(NotificationChannelGroup left, NotificationChannelGroup right) {
|
||||||
|
// Non-grouped channels (in placeholder group with a null id) come last
|
||||||
|
if (left.getId() == null && right.getId() != null) {
|
||||||
|
return 1;
|
||||||
|
} else if (right.getId() == null && left.getId() != null) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return left.getId().compareTo(right.getId());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final Comparator<NotificationChannel> CHANNEL_COMPARATOR = (left, right) -> {
|
||||||
|
if (left.isDeleted() != right.isDeleted()) {
|
||||||
|
return Boolean.compare(left.isDeleted(), right.isDeleted());
|
||||||
|
} else if (left.getId().equals(NotificationChannel.DEFAULT_CHANNEL_ID)) {
|
||||||
|
// Uncategorized/miscellaneous legacy channel goes last
|
||||||
|
return 1;
|
||||||
|
} else if (right.getId().equals(NotificationChannel.DEFAULT_CHANNEL_ID)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return left.getId().compareTo(right.getId());
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@@ -44,7 +44,7 @@ public class ZenCustomRuleCallsSettings extends ZenCustomRuleSettingsBase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int getPreferenceScreenResId() {
|
protected int getPreferenceScreenResId() {
|
||||||
return com.android.settings.R.xml.zen_mode_calls_settings;
|
return com.android.settings.R.xml.zen_mode_custom_rule_calls_settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -37,7 +37,7 @@ public class ZenCustomRuleMessagesSettings extends ZenCustomRuleSettingsBase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int getPreferenceScreenResId() {
|
protected int getPreferenceScreenResId() {
|
||||||
return com.android.settings.R.xml.zen_mode_messages_settings;
|
return com.android.settings.R.xml.zen_mode_custom_rule_messages_settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -0,0 +1,228 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.notification.zen;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.app.settings.SettingsEnums;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
import androidx.core.text.BidiFormatter;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.preference.Preference;
|
||||||
|
import androidx.preference.PreferenceCategory;
|
||||||
|
import androidx.preference.PreferenceScreen;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.applications.AppInfoBase;
|
||||||
|
import com.android.settings.core.PreferenceControllerMixin;
|
||||||
|
import com.android.settings.core.SubSettingLauncher;
|
||||||
|
import com.android.settings.notification.NotificationBackend;
|
||||||
|
import com.android.settings.notification.app.AppChannelsBypassingDndSettings;
|
||||||
|
import com.android.settingslib.applications.ApplicationsState;
|
||||||
|
import com.android.settingslib.core.AbstractPreferenceController;
|
||||||
|
import com.android.settingslib.widget.apppreference.AppPreference;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When clicked, populates the PreferenceScreen with apps that aren't already bypassing DND. The
|
||||||
|
* user can click on these Preferences to allow notification channels from the app to bypass DND.
|
||||||
|
*/
|
||||||
|
public class ZenModeAddBypassingAppsPreferenceController extends AbstractPreferenceController
|
||||||
|
implements PreferenceControllerMixin {
|
||||||
|
|
||||||
|
private static final String KEY = "zen_mode_non_bypassing_apps_list";
|
||||||
|
private static final String KEY_ADD = "zen_mode_bypassing_apps_add";
|
||||||
|
private final NotificationBackend mNotificationBackend;
|
||||||
|
|
||||||
|
@VisibleForTesting ApplicationsState mApplicationsState;
|
||||||
|
@VisibleForTesting PreferenceScreen mPreferenceScreen;
|
||||||
|
@VisibleForTesting PreferenceCategory mPreferenceCategory;
|
||||||
|
@VisibleForTesting Context mPrefContext;
|
||||||
|
|
||||||
|
private Preference mAddPreference;
|
||||||
|
private ApplicationsState.Session mAppSession;
|
||||||
|
private Fragment mHostFragment;
|
||||||
|
|
||||||
|
public ZenModeAddBypassingAppsPreferenceController(Context context, Application app,
|
||||||
|
Fragment host, NotificationBackend notificationBackend) {
|
||||||
|
this(context, app == null ? null : ApplicationsState.getInstance(app), host,
|
||||||
|
notificationBackend);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ZenModeAddBypassingAppsPreferenceController(Context context, ApplicationsState appState,
|
||||||
|
Fragment host, NotificationBackend notificationBackend) {
|
||||||
|
super(context);
|
||||||
|
mNotificationBackend = notificationBackend;
|
||||||
|
mApplicationsState = appState;
|
||||||
|
mHostFragment = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void displayPreference(PreferenceScreen screen) {
|
||||||
|
mPreferenceScreen = screen;
|
||||||
|
mAddPreference = screen.findPreference(KEY_ADD);
|
||||||
|
mAddPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
|
mAddPreference.setVisible(false);
|
||||||
|
if (mApplicationsState != null && mHostFragment != null) {
|
||||||
|
mAppSession = mApplicationsState.newSession(mAppSessionCallbacks,
|
||||||
|
mHostFragment.getLifecycle());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mPrefContext = screen.getContext();
|
||||||
|
super.displayPreference(screen);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPreferenceKey() {
|
||||||
|
return KEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this method to trigger the app list to refresh.
|
||||||
|
*/
|
||||||
|
public void updateAppList() {
|
||||||
|
if (mAppSession == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ApplicationsState.AppFilter filter = ApplicationsState.FILTER_ALL_ENABLED;
|
||||||
|
List<ApplicationsState.AppEntry> apps = mAppSession.rebuild(filter,
|
||||||
|
ApplicationsState.ALPHA_COMPARATOR);
|
||||||
|
updateAppList(apps);
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
void updateAppList(List<ApplicationsState.AppEntry> apps) {
|
||||||
|
if (apps == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mPreferenceCategory == null) {
|
||||||
|
mPreferenceCategory = new PreferenceCategory(mPrefContext);
|
||||||
|
mPreferenceCategory.setTitle(R.string.zen_mode_bypassing_apps_add_header);
|
||||||
|
mPreferenceScreen.addPreference(mPreferenceCategory);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Preference> appsWithNoBypassingDndNotificationChannels = new ArrayList<>();
|
||||||
|
for (ApplicationsState.AppEntry entry : apps) {
|
||||||
|
String pkg = entry.info.packageName;
|
||||||
|
mApplicationsState.ensureIcon(entry);
|
||||||
|
final int appChannels = mNotificationBackend.getChannelCount(pkg, entry.info.uid);
|
||||||
|
final int appChannelsBypassingDnd = mNotificationBackend
|
||||||
|
.getNotificationChannelsBypassingDnd(pkg, entry.info.uid).getList().size();
|
||||||
|
if (appChannelsBypassingDnd == 0 && appChannels > 0) {
|
||||||
|
final String key = ZenModeAllBypassingAppsPreferenceController.getKey(pkg);
|
||||||
|
Preference pref = mPreferenceCategory.findPreference("");
|
||||||
|
if (pref == null) {
|
||||||
|
pref = new AppPreference(mPrefContext);
|
||||||
|
pref.setKey(key);
|
||||||
|
pref.setOnPreferenceClickListener(preference -> {
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
args.putString(AppInfoBase.ARG_PACKAGE_NAME, entry.info.packageName);
|
||||||
|
args.putInt(AppInfoBase.ARG_PACKAGE_UID, entry.info.uid);
|
||||||
|
new SubSettingLauncher(mContext)
|
||||||
|
.setDestination(AppChannelsBypassingDndSettings.class.getName())
|
||||||
|
.setArguments(args)
|
||||||
|
.setResultListener(mHostFragment, 0)
|
||||||
|
.setSourceMetricsCategory(
|
||||||
|
SettingsEnums.NOTIFICATION_ZEN_MODE_OVERRIDING_APP)
|
||||||
|
.launch();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
pref.setTitle(BidiFormatter.getInstance().unicodeWrap(entry.label));
|
||||||
|
pref.setIcon(entry.icon);
|
||||||
|
appsWithNoBypassingDndNotificationChannels.add(pref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (appsWithNoBypassingDndNotificationChannels.size() == 0) {
|
||||||
|
Preference pref = mPreferenceCategory.findPreference(
|
||||||
|
ZenModeAllBypassingAppsPreferenceController.KEY_NO_APPS);
|
||||||
|
if (pref == null) {
|
||||||
|
pref = new Preference(mPrefContext);
|
||||||
|
pref.setKey(ZenModeAllBypassingAppsPreferenceController.KEY_NO_APPS);
|
||||||
|
pref.setTitle(R.string.zen_mode_bypassing_apps_subtext_none);
|
||||||
|
}
|
||||||
|
mPreferenceCategory.addPreference(pref);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ZenModeAllBypassingAppsPreferenceController.hasAppListChanged(
|
||||||
|
appsWithNoBypassingDndNotificationChannels, mPreferenceCategory)) {
|
||||||
|
mPreferenceCategory.removeAll();
|
||||||
|
for (Preference prefToAdd : appsWithNoBypassingDndNotificationChannels) {
|
||||||
|
mPreferenceCategory.addPreference(prefToAdd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ApplicationsState.Callbacks mAppSessionCallbacks =
|
||||||
|
new ApplicationsState.Callbacks() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRunningStateChanged(boolean running) {
|
||||||
|
updateAppList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPackageListChanged() {
|
||||||
|
updateAppList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRebuildComplete(ArrayList<ApplicationsState.AppEntry> apps) {
|
||||||
|
updateAppList(apps);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPackageIconChanged() {
|
||||||
|
updateAppList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPackageSizeChanged(String packageName) {
|
||||||
|
updateAppList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAllSizesComputed() { }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLauncherInfoChanged() {
|
||||||
|
updateAppList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoadEntriesCompleted() {
|
||||||
|
updateAppList();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@@ -17,57 +17,59 @@
|
|||||||
package com.android.settings.notification.zen;
|
package com.android.settings.notification.zen;
|
||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.app.NotificationChannel;
|
|
||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.provider.Settings;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
import androidx.core.text.BidiFormatter;
|
import androidx.core.text.BidiFormatter;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
|
import androidx.preference.PreferenceCategory;
|
||||||
import androidx.preference.PreferenceScreen;
|
import androidx.preference.PreferenceScreen;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.applications.AppInfoBase;
|
import com.android.settings.applications.AppInfoBase;
|
||||||
import com.android.settings.core.PreferenceControllerMixin;
|
import com.android.settings.core.PreferenceControllerMixin;
|
||||||
import com.android.settings.core.SubSettingLauncher;
|
import com.android.settings.core.SubSettingLauncher;
|
||||||
import com.android.settings.notification.app.ChannelNotificationSettings;
|
|
||||||
import com.android.settings.notification.NotificationBackend;
|
import com.android.settings.notification.NotificationBackend;
|
||||||
|
import com.android.settings.notification.app.AppChannelsBypassingDndSettings;
|
||||||
import com.android.settingslib.applications.ApplicationsState;
|
import com.android.settingslib.applications.ApplicationsState;
|
||||||
import com.android.settingslib.core.AbstractPreferenceController;
|
import com.android.settingslib.core.AbstractPreferenceController;
|
||||||
import com.android.settingslib.widget.apppreference.AppPreference;
|
import com.android.settingslib.widget.apppreference.AppPreference;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a preference to the PreferenceScreen for each notification channel that can bypass DND.
|
* Adds a preference to the PreferenceScreen for each notification channel that can bypass DND.
|
||||||
*/
|
*/
|
||||||
public class ZenModeAllBypassingAppsPreferenceController extends AbstractPreferenceController
|
public class ZenModeAllBypassingAppsPreferenceController extends AbstractPreferenceController
|
||||||
implements PreferenceControllerMixin {
|
implements PreferenceControllerMixin {
|
||||||
|
public static final String KEY_NO_APPS = getKey("none");
|
||||||
|
private static final String KEY = "zen_mode_bypassing_apps_list";
|
||||||
|
|
||||||
private final String KEY = "zen_mode_bypassing_apps_category";
|
private final NotificationBackend mNotificationBackend;
|
||||||
|
|
||||||
@VisibleForTesting ApplicationsState mApplicationsState;
|
@VisibleForTesting ApplicationsState mApplicationsState;
|
||||||
@VisibleForTesting PreferenceScreen mPreferenceScreen;
|
@VisibleForTesting PreferenceCategory mPreferenceCategory;
|
||||||
@VisibleForTesting Context mPrefContext;
|
@VisibleForTesting Context mPrefContext;
|
||||||
|
|
||||||
private ApplicationsState.Session mAppSession;
|
private ApplicationsState.Session mAppSession;
|
||||||
private NotificationBackend mNotificationBackend = new NotificationBackend();
|
|
||||||
private Fragment mHostFragment;
|
private Fragment mHostFragment;
|
||||||
|
|
||||||
public ZenModeAllBypassingAppsPreferenceController(Context context, Application app,
|
public ZenModeAllBypassingAppsPreferenceController(Context context, Application app,
|
||||||
Fragment host) {
|
Fragment host, NotificationBackend notificationBackend) {
|
||||||
|
this(context, app == null ? null : ApplicationsState.getInstance(app), host,
|
||||||
this(context, app == null ? null : ApplicationsState.getInstance(app), host);
|
notificationBackend);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ZenModeAllBypassingAppsPreferenceController(Context context, ApplicationsState appState,
|
private ZenModeAllBypassingAppsPreferenceController(Context context, ApplicationsState appState,
|
||||||
Fragment host) {
|
Fragment host, NotificationBackend notificationBackend) {
|
||||||
super(context);
|
super(context);
|
||||||
|
mNotificationBackend = notificationBackend;
|
||||||
mApplicationsState = appState;
|
mApplicationsState = appState;
|
||||||
mHostFragment = host;
|
mHostFragment = host;
|
||||||
|
|
||||||
@@ -78,9 +80,9 @@ public class ZenModeAllBypassingAppsPreferenceController extends AbstractPrefere
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void displayPreference(PreferenceScreen screen) {
|
public void displayPreference(PreferenceScreen screen) {
|
||||||
mPreferenceScreen = screen;
|
mPreferenceCategory = screen.findPreference(KEY);
|
||||||
mPrefContext = mPreferenceScreen.getContext();
|
mPrefContext = screen.getContext();
|
||||||
updateNotificationChannelList();
|
updateAppList();
|
||||||
super.displayPreference(screen);
|
super.displayPreference(screen);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,9 +97,9 @@ public class ZenModeAllBypassingAppsPreferenceController extends AbstractPrefere
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call this method to trigger the notification channels list to refresh.
|
* Call this method to trigger the app list to refresh.
|
||||||
*/
|
*/
|
||||||
public void updateNotificationChannelList() {
|
public void updateAppList() {
|
||||||
if (mAppSession == null) {
|
if (mAppSession == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -105,64 +107,95 @@ public class ZenModeAllBypassingAppsPreferenceController extends AbstractPrefere
|
|||||||
ApplicationsState.AppFilter filter = ApplicationsState.FILTER_ALL_ENABLED;
|
ApplicationsState.AppFilter filter = ApplicationsState.FILTER_ALL_ENABLED;
|
||||||
List<ApplicationsState.AppEntry> apps = mAppSession.rebuild(filter,
|
List<ApplicationsState.AppEntry> apps = mAppSession.rebuild(filter,
|
||||||
ApplicationsState.ALPHA_COMPARATOR);
|
ApplicationsState.ALPHA_COMPARATOR);
|
||||||
updateNotificationChannelList(apps);
|
updateAppList(apps);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void updateNotificationChannelList(List<ApplicationsState.AppEntry> apps) {
|
void updateAppList(List<ApplicationsState.AppEntry> apps) {
|
||||||
if (mPreferenceScreen == null || apps == null) {
|
if (mPreferenceCategory == null || apps == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean showEmptyState = true;
|
List<Preference> appsBypassingDnd = new ArrayList<>();
|
||||||
|
for (ApplicationsState.AppEntry app : apps) {
|
||||||
List<Preference> channelsBypassingDnd = new ArrayList<>();
|
String pkg = app.info.packageName;
|
||||||
for (ApplicationsState.AppEntry entry : apps) {
|
mApplicationsState.ensureIcon(app);
|
||||||
String pkg = entry.info.packageName;
|
final int appChannels = mNotificationBackend.getChannelCount(pkg, app.info.uid);
|
||||||
mApplicationsState.ensureIcon(entry);
|
final int appChannelsBypassingDnd = mNotificationBackend
|
||||||
for (NotificationChannel channel : mNotificationBackend
|
.getNotificationChannelsBypassingDnd(pkg, app.info.uid).getList().size();
|
||||||
.getNotificationChannelsBypassingDnd(pkg, entry.info.uid).getList()) {
|
if (appChannelsBypassingDnd > 0) {
|
||||||
if (!TextUtils.isEmpty(channel.getConversationId())) {
|
final String key = getKey(pkg);
|
||||||
// conversation channels that bypass dnd will be shown on the People page
|
// re-use previously created preference when possible
|
||||||
continue;
|
Preference pref = mPreferenceCategory.findPreference(key);
|
||||||
|
if (pref == null) {
|
||||||
|
pref = new AppPreference(mPrefContext);
|
||||||
|
pref.setKey(key);
|
||||||
|
pref.setOnPreferenceClickListener(preference -> {
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
args.putString(AppInfoBase.ARG_PACKAGE_NAME, app.info.packageName);
|
||||||
|
args.putInt(AppInfoBase.ARG_PACKAGE_UID, app.info.uid);
|
||||||
|
new SubSettingLauncher(mContext)
|
||||||
|
.setDestination(AppChannelsBypassingDndSettings.class.getName())
|
||||||
|
.setArguments(args)
|
||||||
|
.setResultListener(mHostFragment, 0)
|
||||||
|
.setSourceMetricsCategory(
|
||||||
|
SettingsEnums.NOTIFICATION_ZEN_MODE_OVERRIDING_APP)
|
||||||
|
.launch();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
Preference pref = new AppPreference(mPrefContext);
|
pref.setTitle(BidiFormatter.getInstance().unicodeWrap(app.label));
|
||||||
pref.setKey(pkg + "|" + channel.getId());
|
pref.setIcon(app.icon);
|
||||||
pref.setTitle(BidiFormatter.getInstance().unicodeWrap(entry.label));
|
if (appChannels > appChannelsBypassingDnd) {
|
||||||
pref.setIcon(entry.icon);
|
pref.setSummary(R.string.zen_mode_bypassing_apps_summary_some);
|
||||||
pref.setSummary(BidiFormatter.getInstance().unicodeWrap(channel.getName()));
|
} else {
|
||||||
|
pref.setSummary(R.string.zen_mode_bypassing_apps_summary_all);
|
||||||
pref.setOnPreferenceClickListener(preference -> {
|
|
||||||
Bundle args = new Bundle();
|
|
||||||
args.putString(AppInfoBase.ARG_PACKAGE_NAME, entry.info.packageName);
|
|
||||||
args.putInt(AppInfoBase.ARG_PACKAGE_UID, entry.info.uid);
|
|
||||||
args.putString(Settings.EXTRA_CHANNEL_ID, channel.getId());
|
|
||||||
new SubSettingLauncher(mContext)
|
|
||||||
.setDestination(ChannelNotificationSettings.class.getName())
|
|
||||||
.setArguments(args)
|
|
||||||
.setTitleRes(R.string.notification_channel_title)
|
|
||||||
.setResultListener(mHostFragment, 0)
|
|
||||||
.setSourceMetricsCategory(
|
|
||||||
SettingsEnums.NOTIFICATION_ZEN_MODE_OVERRIDING_APP)
|
|
||||||
.launch();
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
channelsBypassingDnd.add(pref);
|
|
||||||
showEmptyState = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mPreferenceScreen.removeAll();
|
|
||||||
if (channelsBypassingDnd.size() > 0) {
|
|
||||||
for (Preference prefToAdd : channelsBypassingDnd) {
|
|
||||||
mPreferenceScreen.addPreference(prefToAdd);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (showEmptyState) {
|
appsBypassingDnd.add(pref);
|
||||||
Preference pref = new Preference(mPrefContext);
|
|
||||||
pref.setTitle(R.string.zen_mode_bypassing_apps_subtext_none);
|
|
||||||
mPreferenceScreen.addPreference(pref);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (appsBypassingDnd.size() == 0) {
|
||||||
|
Preference pref = mPreferenceCategory.findPreference(KEY_NO_APPS);
|
||||||
|
if (pref == null) {
|
||||||
|
pref = new Preference(mPrefContext);
|
||||||
|
pref.setKey(KEY_NO_APPS);
|
||||||
|
pref.setTitle(R.string.zen_mode_bypassing_apps_none);
|
||||||
|
}
|
||||||
|
appsBypassingDnd.add(pref);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasAppListChanged(appsBypassingDnd, mPreferenceCategory)) {
|
||||||
|
mPreferenceCategory.removeAll();
|
||||||
|
for (Preference prefToAdd : appsBypassingDnd) {
|
||||||
|
mPreferenceCategory.addPreference(prefToAdd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean hasAppListChanged(List<Preference> newAppPreferences,
|
||||||
|
PreferenceCategory preferenceCategory) {
|
||||||
|
if (newAppPreferences.size() != preferenceCategory.getPreferenceCount()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < newAppPreferences.size(); i++) {
|
||||||
|
Preference newAppPref = newAppPreferences.get(i);
|
||||||
|
Preference pref = preferenceCategory.getPreference(i);
|
||||||
|
if (!Objects.equals(newAppPref.getKey(), pref.getKey())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a unique key to idenfity an AppPreference
|
||||||
|
*/
|
||||||
|
static String getKey(String pkg) {
|
||||||
|
return pkg;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final ApplicationsState.Callbacks mAppSessionCallbacks =
|
private final ApplicationsState.Callbacks mAppSessionCallbacks =
|
||||||
@@ -170,27 +203,27 @@ public class ZenModeAllBypassingAppsPreferenceController extends AbstractPrefere
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRunningStateChanged(boolean running) {
|
public void onRunningStateChanged(boolean running) {
|
||||||
updateNotificationChannelList();
|
updateAppList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPackageListChanged() {
|
public void onPackageListChanged() {
|
||||||
updateNotificationChannelList();
|
updateAppList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRebuildComplete(ArrayList<ApplicationsState.AppEntry> apps) {
|
public void onRebuildComplete(ArrayList<ApplicationsState.AppEntry> apps) {
|
||||||
updateNotificationChannelList(apps);
|
updateAppList(apps);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPackageIconChanged() {
|
public void onPackageIconChanged() {
|
||||||
updateNotificationChannelList();
|
updateAppList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPackageSizeChanged(String packageName) {
|
public void onPackageSizeChanged(String packageName) {
|
||||||
updateNotificationChannelList();
|
updateAppList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -198,12 +231,12 @@ public class ZenModeAllBypassingAppsPreferenceController extends AbstractPrefere
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLauncherInfoChanged() {
|
public void onLauncherInfoChanged() {
|
||||||
updateNotificationChannelList();
|
updateAppList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoadEntriesCompleted() {
|
public void onLoadEntriesCompleted() {
|
||||||
updateNotificationChannelList();
|
updateAppList();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -287,44 +287,15 @@ public class ZenModeBackend {
|
|||||||
|
|
||||||
protected int getAlarmsTotalSilencePeopleSummary(int category) {
|
protected int getAlarmsTotalSilencePeopleSummary(int category) {
|
||||||
if (category == NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES) {
|
if (category == NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES) {
|
||||||
return R.string.zen_mode_from_none_messages;
|
return R.string.zen_mode_from_none;
|
||||||
} else if (category == NotificationManager.Policy.PRIORITY_CATEGORY_CALLS){
|
} else if (category == NotificationManager.Policy.PRIORITY_CATEGORY_CALLS){
|
||||||
return R.string.zen_mode_from_none_calls;
|
return R.string.zen_mode_from_none;
|
||||||
} else if (category == NotificationManager.Policy.PRIORITY_CATEGORY_CONVERSATIONS) {
|
} else if (category == NotificationManager.Policy.PRIORITY_CATEGORY_CONVERSATIONS) {
|
||||||
return R.string.zen_mode_from_no_conversations;
|
return R.string.zen_mode_from_no_conversations;
|
||||||
}
|
}
|
||||||
return R.string.zen_mode_from_none;
|
return R.string.zen_mode_from_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int getContactsSummary(int category) {
|
|
||||||
int contactType = -1;
|
|
||||||
if (category == NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES) {
|
|
||||||
if (isPriorityCategoryEnabled(category)) {
|
|
||||||
contactType = getPriorityMessageSenders();
|
|
||||||
}
|
|
||||||
} else if (category == NotificationManager.Policy.PRIORITY_CATEGORY_CALLS) {
|
|
||||||
if (isPriorityCategoryEnabled(category)) {
|
|
||||||
contactType = getPriorityCallSenders();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (contactType) {
|
|
||||||
case NotificationManager.Policy.PRIORITY_SENDERS_ANY:
|
|
||||||
return R.string.zen_mode_from_anyone;
|
|
||||||
case NotificationManager.Policy.PRIORITY_SENDERS_CONTACTS:
|
|
||||||
return R.string.zen_mode_from_contacts;
|
|
||||||
case NotificationManager.Policy.PRIORITY_SENDERS_STARRED:
|
|
||||||
return R.string.zen_mode_from_starred;
|
|
||||||
case SOURCE_NONE:
|
|
||||||
default:
|
|
||||||
if (category == NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES) {
|
|
||||||
return R.string.zen_mode_from_none_messages;
|
|
||||||
} else {
|
|
||||||
return R.string.zen_mode_from_none_calls;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getConversationSummary() {
|
protected int getConversationSummary() {
|
||||||
int conversationType = getPriorityConversationSenders();
|
int conversationType = getPriorityConversationSenders();
|
||||||
|
|
||||||
@@ -366,7 +337,7 @@ public class ZenModeBackend {
|
|||||||
return R.string.zen_mode_from_starred;
|
return R.string.zen_mode_from_starred;
|
||||||
case ZenPolicy.PEOPLE_TYPE_NONE:
|
case ZenPolicy.PEOPLE_TYPE_NONE:
|
||||||
default:
|
default:
|
||||||
return R.string.zen_mode_from_none_messages;
|
return R.string.zen_mode_from_none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -384,20 +355,6 @@ public class ZenModeBackend {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static int getSettingFromPrefKey(String key) {
|
|
||||||
switch (key) {
|
|
||||||
case ZEN_MODE_FROM_ANYONE:
|
|
||||||
return NotificationManager.Policy.PRIORITY_SENDERS_ANY;
|
|
||||||
case ZEN_MODE_FROM_CONTACTS:
|
|
||||||
return NotificationManager.Policy.PRIORITY_SENDERS_CONTACTS;
|
|
||||||
case ZEN_MODE_FROM_STARRED:
|
|
||||||
return NotificationManager.Policy.PRIORITY_SENDERS_STARRED;
|
|
||||||
case ZEN_MODE_FROM_NONE:
|
|
||||||
default:
|
|
||||||
return SOURCE_NONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean removeZenRule(String ruleId) {
|
public boolean removeZenRule(String ruleId) {
|
||||||
return NotificationManager.from(mContext).removeAutomaticZenRule(ruleId);
|
return NotificationManager.from(mContext).removeAutomaticZenRule(ruleId);
|
||||||
}
|
}
|
||||||
|
@@ -6,6 +6,7 @@ import android.content.Context;
|
|||||||
import android.icu.text.ListFormatter;
|
import android.icu.text.ListFormatter;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.util.ArraySet;
|
||||||
|
|
||||||
import androidx.core.text.BidiFormatter;
|
import androidx.core.text.BidiFormatter;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
@@ -21,6 +22,7 @@ import com.android.settingslib.core.lifecycle.Lifecycle;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controls the summary for preference found at:
|
* Controls the summary for preference found at:
|
||||||
@@ -102,7 +104,7 @@ public class ZenModeBypassingAppsPreferenceController extends AbstractZenModePre
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> appsBypassingDnd = new ArrayList<>();
|
Set<String> appsBypassingDnd = new ArraySet<>();
|
||||||
for (ApplicationsState.AppEntry entry : apps) {
|
for (ApplicationsState.AppEntry entry : apps) {
|
||||||
String pkg = entry.info.packageName;
|
String pkg = entry.info.packageName;
|
||||||
for (NotificationChannel channel : mNotificationBackend
|
for (NotificationChannel channel : mNotificationBackend
|
||||||
@@ -116,7 +118,8 @@ public class ZenModeBypassingAppsPreferenceController extends AbstractZenModePre
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (appsBypassingDnd.size() == 0) {
|
final int numAppsBypassingDnd = appsBypassingDnd.size();
|
||||||
|
if (numAppsBypassingDnd == 0) {
|
||||||
mSummary = mContext.getResources().getString(
|
mSummary = mContext.getResources().getString(
|
||||||
R.string.zen_mode_bypassing_apps_subtext_none);
|
R.string.zen_mode_bypassing_apps_subtext_none);
|
||||||
refreshSummary(mPreference);
|
refreshSummary(mPreference);
|
||||||
@@ -124,18 +127,20 @@ public class ZenModeBypassingAppsPreferenceController extends AbstractZenModePre
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<String> displayAppsBypassing = new ArrayList<>();
|
List<String> displayAppsBypassing = new ArrayList<>();
|
||||||
if (appsBypassingDnd.size() <= 2) {
|
if (numAppsBypassingDnd <= 2) {
|
||||||
displayAppsBypassing = appsBypassingDnd;
|
displayAppsBypassing.addAll(appsBypassingDnd);
|
||||||
} else {
|
} else {
|
||||||
displayAppsBypassing.add(appsBypassingDnd.get(0));
|
String[] appsBypassingDndArr =
|
||||||
displayAppsBypassing.add(appsBypassingDnd.get(1));
|
appsBypassingDnd.toArray(new String[numAppsBypassingDnd]);
|
||||||
|
displayAppsBypassing.add(appsBypassingDndArr[0]);
|
||||||
|
displayAppsBypassing.add(appsBypassingDndArr[1]);
|
||||||
displayAppsBypassing.add(mContext.getResources().getString(
|
displayAppsBypassing.add(mContext.getResources().getString(
|
||||||
R.string.zen_mode_apps_bypassing_list_count,
|
R.string.zen_mode_apps_bypassing_list_count,
|
||||||
appsBypassingDnd.size() - 2));
|
numAppsBypassingDnd - 2));
|
||||||
}
|
}
|
||||||
mSummary = mContext.getResources().getQuantityString(
|
mSummary = mContext.getResources().getQuantityString(
|
||||||
R.plurals.zen_mode_bypassing_apps_subtext,
|
R.plurals.zen_mode_bypassing_apps_subtext,
|
||||||
appsBypassingDnd.size(),
|
numAppsBypassingDnd,
|
||||||
ListFormatter.getInstance().format(displayAppsBypassing));
|
ListFormatter.getInstance().format(displayAppsBypassing));
|
||||||
refreshSummary(mPreference);
|
refreshSummary(mPreference);
|
||||||
}
|
}
|
||||||
|
@@ -24,6 +24,7 @@ import android.content.Context;
|
|||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.notification.NotificationBackend;
|
||||||
import com.android.settings.search.BaseSearchIndexProvider;
|
import com.android.settings.search.BaseSearchIndexProvider;
|
||||||
import com.android.settingslib.core.AbstractPreferenceController;
|
import com.android.settingslib.core.AbstractPreferenceController;
|
||||||
import com.android.settingslib.search.Indexable;
|
import com.android.settingslib.search.Indexable;
|
||||||
@@ -46,13 +47,16 @@ public class ZenModeBypassingAppsSettings extends ZenModeSettingsBase implements
|
|||||||
} else {
|
} else {
|
||||||
app = null;
|
app = null;
|
||||||
}
|
}
|
||||||
return buildPreferenceControllers(context, app, this);
|
return buildPreferenceControllers(context, app, this, new NotificationBackend());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
|
private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
|
||||||
Application app, Fragment host) {
|
Application app, Fragment host, NotificationBackend notificationBackend) {
|
||||||
final List<AbstractPreferenceController> controllers = new ArrayList<>();
|
final List<AbstractPreferenceController> controllers = new ArrayList<>();
|
||||||
controllers.add(new ZenModeAllBypassingAppsPreferenceController(context, app, host));
|
controllers.add(new ZenModeAllBypassingAppsPreferenceController(context, app, host,
|
||||||
|
notificationBackend));
|
||||||
|
controllers.add(new ZenModeAddBypassingAppsPreferenceController(context, app, host,
|
||||||
|
notificationBackend));
|
||||||
return controllers;
|
return controllers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +84,7 @@ public class ZenModeBypassingAppsSettings extends ZenModeSettingsBase implements
|
|||||||
@Override
|
@Override
|
||||||
public List<AbstractPreferenceController> createPreferenceControllers(
|
public List<AbstractPreferenceController> createPreferenceControllers(
|
||||||
Context context) {
|
Context context) {
|
||||||
return buildPreferenceControllers(context, null, null);
|
return buildPreferenceControllers(context, null, null, null);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -30,7 +30,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Settings > Sound > Do Not Disturb > Conversationss
|
* Settings > Sound > Do Not Disturb > Conversations
|
||||||
*/
|
*/
|
||||||
@SearchIndexable
|
@SearchIndexable
|
||||||
public class ZenModeConversationsSettings extends ZenModeSettingsBase {
|
public class ZenModeConversationsSettings extends ZenModeSettingsBase {
|
||||||
|
@@ -1,108 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2018 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.notification.zen;
|
|
||||||
|
|
||||||
import android.app.NotificationManager;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.provider.Settings;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
|
||||||
import androidx.preference.ListPreference;
|
|
||||||
import androidx.preference.Preference;
|
|
||||||
import androidx.preference.PreferenceScreen;
|
|
||||||
|
|
||||||
import com.android.settings.R;
|
|
||||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
|
||||||
|
|
||||||
public class ZenModePriorityCallsPreferenceController extends AbstractZenModePreferenceController
|
|
||||||
implements Preference.OnPreferenceChangeListener {
|
|
||||||
|
|
||||||
protected static final String KEY = "zen_mode_calls";
|
|
||||||
private final ZenModeBackend mBackend;
|
|
||||||
private ListPreference mPreference;
|
|
||||||
private final String[] mListValues;
|
|
||||||
|
|
||||||
public ZenModePriorityCallsPreferenceController(Context context, Lifecycle lifecycle) {
|
|
||||||
super(context, KEY, lifecycle);
|
|
||||||
mBackend = ZenModeBackend.getInstance(context);
|
|
||||||
mListValues = context.getResources().getStringArray(R.array.zen_mode_contacts_values);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getPreferenceKey() {
|
|
||||||
return KEY;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isAvailable() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void displayPreference(PreferenceScreen screen) {
|
|
||||||
super.displayPreference(screen);
|
|
||||||
mPreference = screen.findPreference(KEY);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateState(Preference preference) {
|
|
||||||
super.updateState(preference);
|
|
||||||
updateFromContactsValue(preference);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onPreferenceChange(Preference preference, Object selectedContactsFrom) {
|
|
||||||
mBackend.saveSenders(NotificationManager.Policy.PRIORITY_CATEGORY_CALLS,
|
|
||||||
ZenModeBackend.getSettingFromPrefKey(selectedContactsFrom.toString()));
|
|
||||||
updateFromContactsValue(preference);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateFromContactsValue(Preference preference) {
|
|
||||||
mPreference = (ListPreference) preference;
|
|
||||||
switch (getZenMode()) {
|
|
||||||
case Settings.Global.ZEN_MODE_NO_INTERRUPTIONS:
|
|
||||||
case Settings.Global.ZEN_MODE_ALARMS:
|
|
||||||
mPreference.setEnabled(false);
|
|
||||||
mPreference.setValue(ZenModeBackend.ZEN_MODE_FROM_NONE);
|
|
||||||
mPreference.setSummary(mBackend.getAlarmsTotalSilencePeopleSummary(
|
|
||||||
NotificationManager.Policy.PRIORITY_CATEGORY_CALLS));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
preference.setEnabled(true);
|
|
||||||
preference.setSummary(mBackend.getContactsSummary(
|
|
||||||
NotificationManager.Policy.PRIORITY_CATEGORY_CALLS));
|
|
||||||
|
|
||||||
final String currentVal = ZenModeBackend.getKeyFromSetting(
|
|
||||||
mBackend.getPriorityCallSenders());
|
|
||||||
mPreference.setValue(mListValues[getIndexOfSendersValue(currentVal)]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
protected int getIndexOfSendersValue(String currentVal) {
|
|
||||||
int index = 3; // defaults to "none" based on R.array.zen_mode_contacts_values
|
|
||||||
for (int i = 0; i < mListValues.length; i++) {
|
|
||||||
if (TextUtils.equals(currentVal, mListValues[i])) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -16,11 +16,16 @@
|
|||||||
|
|
||||||
package com.android.settings.notification.zen;
|
package com.android.settings.notification.zen;
|
||||||
|
|
||||||
|
import static com.android.settings.widget.RadioButtonPreferenceWithExtraWidget.EXTRA_WIDGET_VISIBILITY_GONE;
|
||||||
|
import static com.android.settings.widget.RadioButtonPreferenceWithExtraWidget.EXTRA_WIDGET_VISIBILITY_SETTING;
|
||||||
|
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
|
import android.app.settings.SettingsEnums;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.ParceledListSlice;
|
import android.content.pm.ParceledListSlice;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.service.notification.ConversationChannelWrapper;
|
import android.service.notification.ConversationChannelWrapper;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
@@ -28,7 +33,10 @@ import androidx.preference.PreferenceCategory;
|
|||||||
import androidx.preference.PreferenceScreen;
|
import androidx.preference.PreferenceScreen;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.core.SubSettingLauncher;
|
||||||
import com.android.settings.notification.NotificationBackend;
|
import com.android.settings.notification.NotificationBackend;
|
||||||
|
import com.android.settings.notification.app.ConversationListSettings;
|
||||||
|
import com.android.settings.widget.RadioButtonPreferenceWithExtraWidget;
|
||||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||||
import com.android.settingslib.widget.RadioButtonPreference;
|
import com.android.settingslib.widget.RadioButtonPreference;
|
||||||
|
|
||||||
@@ -51,6 +59,7 @@ public class ZenModePriorityConversationsPreferenceController
|
|||||||
private int mNumConversations = UNSET;
|
private int mNumConversations = UNSET;
|
||||||
private PreferenceCategory mPreferenceCategory;
|
private PreferenceCategory mPreferenceCategory;
|
||||||
private List<RadioButtonPreference> mRadioButtonPreferences = new ArrayList<>();
|
private List<RadioButtonPreference> mRadioButtonPreferences = new ArrayList<>();
|
||||||
|
private Context mPreferenceScreenContext;
|
||||||
|
|
||||||
public ZenModePriorityConversationsPreferenceController(Context context, String key,
|
public ZenModePriorityConversationsPreferenceController(Context context, String key,
|
||||||
Lifecycle lifecycle, NotificationBackend notificationBackend) {
|
Lifecycle lifecycle, NotificationBackend notificationBackend) {
|
||||||
@@ -60,6 +69,7 @@ public class ZenModePriorityConversationsPreferenceController
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void displayPreference(PreferenceScreen screen) {
|
public void displayPreference(PreferenceScreen screen) {
|
||||||
|
mPreferenceScreenContext = screen.getContext();
|
||||||
mPreferenceCategory = screen.findPreference(getPreferenceKey());
|
mPreferenceCategory = screen.findPreference(getPreferenceKey());
|
||||||
if (mPreferenceCategory.findPreference(KEY_ALL) == null) {
|
if (mPreferenceCategory.findPreference(KEY_ALL) == null) {
|
||||||
makeRadioPreference(KEY_ALL, R.string.zen_mode_from_all_conversations);
|
makeRadioPreference(KEY_ALL, R.string.zen_mode_from_all_conversations);
|
||||||
@@ -125,7 +135,7 @@ public class ZenModePriorityConversationsPreferenceController
|
|||||||
R.string.zen_mode_conversations_count_none);
|
R.string.zen_mode_conversations_count_none);
|
||||||
} else {
|
} else {
|
||||||
return mContext.getResources().getQuantityString(
|
return mContext.getResources().getQuantityString(
|
||||||
R.plurals.zen_mode_conversations_count, numConversations);
|
R.plurals.zen_mode_conversations_count, numConversations, numConversations);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,14 +146,27 @@ public class ZenModePriorityConversationsPreferenceController
|
|||||||
protected Void doInBackground(Void... unused) {
|
protected Void doInBackground(Void... unused) {
|
||||||
ParceledListSlice<ConversationChannelWrapper> allConversations =
|
ParceledListSlice<ConversationChannelWrapper> allConversations =
|
||||||
mNotificationBackend.getConversations(false);
|
mNotificationBackend.getConversations(false);
|
||||||
|
int numConversations = 0;
|
||||||
if (allConversations != null) {
|
if (allConversations != null) {
|
||||||
mNumConversations = allConversations.getList().size();
|
for (ConversationChannelWrapper conversation : allConversations.getList()) {
|
||||||
|
if (!conversation.getNotificationChannel().isDemoted()) {
|
||||||
|
numConversations++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ParceledListSlice<ConversationChannelWrapper> importantConversations =
|
mNumConversations = numConversations;
|
||||||
|
|
||||||
|
ParceledListSlice<ConversationChannelWrapper> impConversations =
|
||||||
mNotificationBackend.getConversations(true);
|
mNotificationBackend.getConversations(true);
|
||||||
if (importantConversations != null) {
|
int numImportantConversations = 0;
|
||||||
mNumImportantConversations = importantConversations.getList().size();
|
if (impConversations != null) {
|
||||||
|
for (ConversationChannelWrapper conversation : impConversations.getList()) {
|
||||||
|
if (!conversation.getNotificationChannel().isDemoted()) {
|
||||||
|
numImportantConversations++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
mNumImportantConversations = numImportantConversations;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,7 +181,14 @@ public class ZenModePriorityConversationsPreferenceController
|
|||||||
}
|
}
|
||||||
|
|
||||||
private RadioButtonPreference makeRadioPreference(String key, int titleId) {
|
private RadioButtonPreference makeRadioPreference(String key, int titleId) {
|
||||||
RadioButtonPreference pref = new RadioButtonPreference(mPreferenceCategory.getContext());
|
RadioButtonPreferenceWithExtraWidget pref =
|
||||||
|
new RadioButtonPreferenceWithExtraWidget(mPreferenceCategory.getContext());
|
||||||
|
if (KEY_ALL.equals(key) || KEY_IMPORTANT.equals(key)) {
|
||||||
|
pref.setExtraWidgetOnClickListener(mConversationSettingsWidgetClickListener);
|
||||||
|
pref.setExtraWidgetVisibility(EXTRA_WIDGET_VISIBILITY_SETTING);
|
||||||
|
} else {
|
||||||
|
pref.setExtraWidgetVisibility(EXTRA_WIDGET_VISIBILITY_GONE);
|
||||||
|
}
|
||||||
pref.setKey(key);
|
pref.setKey(key);
|
||||||
pref.setTitle(titleId);
|
pref.setTitle(titleId);
|
||||||
pref.setOnClickListener(mRadioButtonClickListener);
|
pref.setOnClickListener(mRadioButtonClickListener);
|
||||||
@@ -167,6 +197,17 @@ public class ZenModePriorityConversationsPreferenceController
|
|||||||
return pref;
|
return pref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private View.OnClickListener mConversationSettingsWidgetClickListener =
|
||||||
|
new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
new SubSettingLauncher(mPreferenceScreenContext)
|
||||||
|
.setDestination(ConversationListSettings.class.getName())
|
||||||
|
.setSourceMetricsCategory(SettingsEnums.DND_CONVERSATIONS)
|
||||||
|
.launch();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private RadioButtonPreference.OnClickListener mRadioButtonClickListener =
|
private RadioButtonPreference.OnClickListener mRadioButtonClickListener =
|
||||||
new RadioButtonPreference.OnClickListener() {
|
new RadioButtonPreference.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
|
@@ -153,7 +153,7 @@ public class ZenModeSettings extends ZenModeSettingsBase {
|
|||||||
String getCallsSettingSummary(Policy policy) {
|
String getCallsSettingSummary(Policy policy) {
|
||||||
List<String> enabledCategories = getEnabledCategories(policy,
|
List<String> enabledCategories = getEnabledCategories(policy,
|
||||||
category -> PRIORITY_CATEGORY_CALLS == category
|
category -> PRIORITY_CATEGORY_CALLS == category
|
||||||
|| PRIORITY_CATEGORY_REPEAT_CALLERS == category, false);
|
|| PRIORITY_CATEGORY_REPEAT_CALLERS == category, true);
|
||||||
int numCategories = enabledCategories.size();
|
int numCategories = enabledCategories.size();
|
||||||
if (numCategories == 0) {
|
if (numCategories == 0) {
|
||||||
return mContext.getString(R.string.zen_mode_from_none_calls);
|
return mContext.getString(R.string.zen_mode_from_none_calls);
|
||||||
@@ -303,10 +303,19 @@ public class ZenModeSettings extends ZenModeSettingsBase {
|
|||||||
}
|
}
|
||||||
} else if (category == Policy.PRIORITY_CATEGORY_CALLS) {
|
} else if (category == Policy.PRIORITY_CATEGORY_CALLS) {
|
||||||
if (policy.priorityCallSenders == Policy.PRIORITY_SENDERS_ANY) {
|
if (policy.priorityCallSenders == Policy.PRIORITY_SENDERS_ANY) {
|
||||||
|
if (isFirst) {
|
||||||
|
return mContext.getString(R.string.zen_mode_from_anyone);
|
||||||
|
}
|
||||||
return mContext.getString(R.string.zen_mode_all_callers);
|
return mContext.getString(R.string.zen_mode_all_callers);
|
||||||
} else if (policy.priorityCallSenders == Policy.PRIORITY_SENDERS_CONTACTS){
|
} else if (policy.priorityCallSenders == Policy.PRIORITY_SENDERS_CONTACTS){
|
||||||
|
if (isFirst) {
|
||||||
|
return mContext.getString(R.string.zen_mode_from_contacts);
|
||||||
|
}
|
||||||
return mContext.getString(R.string.zen_mode_contacts_callers);
|
return mContext.getString(R.string.zen_mode_contacts_callers);
|
||||||
} else {
|
} else {
|
||||||
|
if (isFirst) {
|
||||||
|
return mContext.getString(R.string.zen_mode_from_starred);
|
||||||
|
}
|
||||||
return mContext.getString(R.string.zen_mode_starred_callers);
|
return mContext.getString(R.string.zen_mode_starred_callers);
|
||||||
}
|
}
|
||||||
} else if (category == Policy.PRIORITY_CATEGORY_REPEAT_CALLERS) {
|
} else if (category == Policy.PRIORITY_CATEGORY_REPEAT_CALLERS) {
|
||||||
|
@@ -16,19 +16,8 @@
|
|||||||
|
|
||||||
package com.android.settings.notification.app;
|
package com.android.settings.notification.app;
|
||||||
|
|
||||||
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
|
|
||||||
import static android.app.NotificationManager.IMPORTANCE_HIGH;
|
|
||||||
import static android.app.NotificationManager.IMPORTANCE_LOW;
|
|
||||||
import static android.app.NotificationManager.IMPORTANCE_MIN;
|
|
||||||
import static android.app.NotificationManager.IMPORTANCE_NONE;
|
|
||||||
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
|
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
|
||||||
import static org.mockito.Mockito.any;
|
import static org.mockito.Mockito.any;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
@@ -37,24 +26,17 @@ import static org.mockito.Mockito.verify;
|
|||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import android.app.NotificationChannel;
|
import android.app.NotificationChannel;
|
||||||
import android.app.NotificationChannelGroup;
|
|
||||||
import android.app.NotificationManager;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.ShortcutInfo;
|
import android.content.pm.ShortcutInfo;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.UserManager;
|
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.service.notification.ConversationChannelWrapper;
|
import android.service.notification.ConversationChannelWrapper;
|
||||||
import android.view.View;
|
|
||||||
|
|
||||||
import androidx.preference.Preference;
|
|
||||||
import androidx.preference.PreferenceCategory;
|
import androidx.preference.PreferenceCategory;
|
||||||
import androidx.preference.PreferenceGroup;
|
|
||||||
|
|
||||||
import com.android.settings.applications.AppInfoBase;
|
import com.android.settings.applications.AppInfoBase;
|
||||||
import com.android.settings.notification.NotificationBackend;
|
import com.android.settings.notification.NotificationBackend;
|
||||||
import com.android.settingslib.RestrictedLockUtils;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -67,7 +49,6 @@ import org.robolectric.RuntimeEnvironment;
|
|||||||
import org.robolectric.shadows.ShadowApplication;
|
import org.robolectric.shadows.ShadowApplication;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
public class ConversationListPreferenceControllerTest {
|
public class ConversationListPreferenceControllerTest {
|
||||||
@@ -116,8 +97,6 @@ public class ConversationListPreferenceControllerTest {
|
|||||||
list.add(ccw);
|
list.add(ccw);
|
||||||
|
|
||||||
mController.populateList(list, outerContainer);
|
mController.populateList(list, outerContainer);
|
||||||
|
|
||||||
verify(outerContainer).setVisible(true);
|
|
||||||
verify(outerContainer, times(1)).addPreference(any());
|
verify(outerContainer, times(1)).addPreference(any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -0,0 +1,164 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.notification.zen;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.ParceledListSlice;
|
||||||
|
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.preference.Preference;
|
||||||
|
import androidx.preference.PreferenceCategory;
|
||||||
|
|
||||||
|
import com.android.settings.notification.NotificationBackend;
|
||||||
|
import com.android.settingslib.applications.ApplicationsState;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
public class ZenModeAddBypassingAppsPreferenceControllerTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private NotificationBackend mBackend;
|
||||||
|
@Mock
|
||||||
|
private PreferenceCategory mPreferenceCategory;
|
||||||
|
@Mock
|
||||||
|
private ApplicationsState mApplicationState;
|
||||||
|
private ZenModeAddBypassingAppsPreferenceController mController;
|
||||||
|
private Context mContext;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
mContext = RuntimeEnvironment.application;
|
||||||
|
|
||||||
|
mController = new ZenModeAddBypassingAppsPreferenceController(
|
||||||
|
mContext, null, mock(Fragment.class), mBackend);
|
||||||
|
mController.mPreferenceCategory = mPreferenceCategory;
|
||||||
|
mController.mApplicationsState = mApplicationState;
|
||||||
|
mController.mPrefContext = mContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable() {
|
||||||
|
assertThat(mController.isAvailable()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateAppList() {
|
||||||
|
// GIVEN there's an app with bypassing channels, app without any channels, and then an app
|
||||||
|
// with notification channels but none that can bypass DND
|
||||||
|
ApplicationsState.AppEntry appWithBypassingChannels =
|
||||||
|
mock(ApplicationsState.AppEntry.class);
|
||||||
|
appWithBypassingChannels.info = new ApplicationInfo();
|
||||||
|
appWithBypassingChannels.info.packageName = "appWithBypassingChannels";
|
||||||
|
appWithBypassingChannels.info.uid = 0;
|
||||||
|
when(mBackend.getNotificationChannelsBypassingDnd(
|
||||||
|
appWithBypassingChannels.info.packageName,
|
||||||
|
appWithBypassingChannels.info.uid))
|
||||||
|
.thenReturn(new ParceledListSlice<>(
|
||||||
|
Arrays.asList(mock(NotificationChannel.class))));
|
||||||
|
when(mBackend.getChannelCount(
|
||||||
|
appWithBypassingChannels.info.packageName,
|
||||||
|
appWithBypassingChannels.info.uid))
|
||||||
|
.thenReturn(5);
|
||||||
|
|
||||||
|
ApplicationsState.AppEntry appWithoutChannels = mock(ApplicationsState.AppEntry.class);
|
||||||
|
appWithoutChannels.info = new ApplicationInfo();
|
||||||
|
appWithoutChannels.info.packageName = "appWithoutChannels";
|
||||||
|
appWithoutChannels.info.uid = 0;
|
||||||
|
when(mBackend.getChannelCount(
|
||||||
|
appWithoutChannels.info.packageName,
|
||||||
|
appWithoutChannels.info.uid))
|
||||||
|
.thenReturn(0);
|
||||||
|
when(mBackend.getNotificationChannelsBypassingDnd(
|
||||||
|
appWithoutChannels.info.packageName,
|
||||||
|
appWithoutChannels.info.uid))
|
||||||
|
.thenReturn(new ParceledListSlice<>(new ArrayList<>()));
|
||||||
|
|
||||||
|
ApplicationsState.AppEntry appWithChannelsNoneBypassing =
|
||||||
|
mock(ApplicationsState.AppEntry.class);
|
||||||
|
appWithChannelsNoneBypassing.info = new ApplicationInfo();
|
||||||
|
appWithChannelsNoneBypassing.info.packageName = "appWithChannelsNoneBypassing";
|
||||||
|
appWithChannelsNoneBypassing.info.uid = 0;
|
||||||
|
when(mBackend.getChannelCount(
|
||||||
|
appWithChannelsNoneBypassing.info.packageName,
|
||||||
|
appWithChannelsNoneBypassing.info.uid))
|
||||||
|
.thenReturn(5);
|
||||||
|
when(mBackend.getNotificationChannelsBypassingDnd(
|
||||||
|
appWithChannelsNoneBypassing.info.packageName,
|
||||||
|
appWithChannelsNoneBypassing.info.uid))
|
||||||
|
.thenReturn(new ParceledListSlice<>(new ArrayList<>()));
|
||||||
|
|
||||||
|
List<ApplicationsState.AppEntry> appEntries = new ArrayList<>();
|
||||||
|
appEntries.add(appWithBypassingChannels);
|
||||||
|
appEntries.add(appWithoutChannels);
|
||||||
|
appEntries.add(appWithChannelsNoneBypassing);
|
||||||
|
|
||||||
|
// WHEN the controller updates the app list with the app entries
|
||||||
|
mController.updateAppList(appEntries);
|
||||||
|
|
||||||
|
// THEN only the appWithChannelsNoneBypassing makes it to the app list
|
||||||
|
ArgumentCaptor<Preference> prefCaptor = ArgumentCaptor.forClass(Preference.class);
|
||||||
|
verify(mPreferenceCategory).addPreference(prefCaptor.capture());
|
||||||
|
|
||||||
|
Preference pref = prefCaptor.getValue();
|
||||||
|
assertThat(pref.getKey()).isEqualTo(
|
||||||
|
ZenModeAllBypassingAppsPreferenceController.getKey(
|
||||||
|
appWithChannelsNoneBypassing.info.packageName));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateAppList_nullApps() {
|
||||||
|
mController.updateAppList(null);
|
||||||
|
verify(mPreferenceCategory, never()).addPreference(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateAppList_emptyAppList() {
|
||||||
|
// WHEN there are no apps
|
||||||
|
mController.updateAppList(new ArrayList<>());
|
||||||
|
|
||||||
|
// THEN only the appWithChannelsNoneBypassing makes it to the app list
|
||||||
|
ArgumentCaptor<Preference> prefCaptor = ArgumentCaptor.forClass(Preference.class);
|
||||||
|
verify(mPreferenceCategory).addPreference(prefCaptor.capture());
|
||||||
|
|
||||||
|
Preference pref = prefCaptor.getValue();
|
||||||
|
assertThat(pref.getKey()).isEqualTo(
|
||||||
|
ZenModeAllBypassingAppsPreferenceController.KEY_NO_APPS);
|
||||||
|
}
|
||||||
|
}
|
@@ -19,6 +19,8 @@ package com.android.settings.notification.zen;
|
|||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
@@ -30,25 +32,25 @@ import android.content.Context;
|
|||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.ParceledListSlice;
|
import android.content.pm.ParceledListSlice;
|
||||||
|
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.preference.Preference;
|
||||||
|
import androidx.preference.PreferenceCategory;
|
||||||
|
|
||||||
import com.android.settings.notification.NotificationBackend;
|
import com.android.settings.notification.NotificationBackend;
|
||||||
import com.android.settings.notification.zen.ZenModeAllBypassingAppsPreferenceController;
|
|
||||||
import com.android.settingslib.applications.ApplicationsState;
|
import com.android.settingslib.applications.ApplicationsState;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
import org.robolectric.RuntimeEnvironment;
|
import org.robolectric.RuntimeEnvironment;
|
||||||
import org.robolectric.util.ReflectionHelpers;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import androidx.fragment.app.Fragment;
|
|
||||||
import androidx.preference.PreferenceScreen;
|
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
public class ZenModeAllBypassingAppsPreferenceControllerTest {
|
public class ZenModeAllBypassingAppsPreferenceControllerTest {
|
||||||
private ZenModeAllBypassingAppsPreferenceController mController;
|
private ZenModeAllBypassingAppsPreferenceController mController;
|
||||||
@@ -57,7 +59,7 @@ public class ZenModeAllBypassingAppsPreferenceControllerTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private NotificationBackend mBackend;
|
private NotificationBackend mBackend;
|
||||||
@Mock
|
@Mock
|
||||||
private PreferenceScreen mPreferenceScreen;
|
private PreferenceCategory mPreferenceCategory;
|
||||||
@Mock
|
@Mock
|
||||||
private ApplicationsState mApplicationState;
|
private ApplicationsState mApplicationState;
|
||||||
|
|
||||||
@@ -67,11 +69,10 @@ public class ZenModeAllBypassingAppsPreferenceControllerTest {
|
|||||||
mContext = RuntimeEnvironment.application;
|
mContext = RuntimeEnvironment.application;
|
||||||
|
|
||||||
mController = new ZenModeAllBypassingAppsPreferenceController(
|
mController = new ZenModeAllBypassingAppsPreferenceController(
|
||||||
mContext, null, mock(Fragment.class));
|
mContext, null, mock(Fragment.class), mBackend);
|
||||||
mController.mPreferenceScreen = mPreferenceScreen;
|
mController.mPreferenceCategory = mPreferenceCategory;
|
||||||
mController.mApplicationsState = mApplicationState;
|
mController.mApplicationsState = mApplicationState;
|
||||||
mController.mPrefContext = mContext;
|
mController.mPrefContext = mContext;
|
||||||
ReflectionHelpers.setField(mController, "mNotificationBackend", mBackend);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -80,36 +81,49 @@ public class ZenModeAllBypassingAppsPreferenceControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateNotificationChannelList() {
|
public void testUpdateAppList() {
|
||||||
ApplicationsState.AppEntry entry = mock(ApplicationsState.AppEntry.class);
|
// WHEN there's two apps with notification channels that bypass DND
|
||||||
entry.info = new ApplicationInfo();
|
ApplicationsState.AppEntry entry1 = mock(ApplicationsState.AppEntry.class);
|
||||||
entry.info.packageName = "test";
|
entry1.info = new ApplicationInfo();
|
||||||
entry.info.uid = 0;
|
entry1.info.packageName = "test";
|
||||||
|
entry1.info.uid = 0;
|
||||||
|
|
||||||
|
ApplicationsState.AppEntry entry2 = mock(ApplicationsState.AppEntry.class);
|
||||||
|
entry2.info = new ApplicationInfo();
|
||||||
|
entry2.info.packageName = "test2";
|
||||||
|
entry2.info.uid = 0;
|
||||||
|
|
||||||
List<ApplicationsState.AppEntry> appEntries = new ArrayList<>();
|
List<ApplicationsState.AppEntry> appEntries = new ArrayList<>();
|
||||||
appEntries.add(entry);
|
appEntries.add(entry1);
|
||||||
|
appEntries.add(entry2);
|
||||||
List<NotificationChannel> channelsBypassing = new ArrayList<>();
|
List<NotificationChannel> channelsBypassing = new ArrayList<>();
|
||||||
channelsBypassing.add(mock(NotificationChannel.class));
|
channelsBypassing.add(mock(NotificationChannel.class));
|
||||||
channelsBypassing.add(mock(NotificationChannel.class));
|
channelsBypassing.add(mock(NotificationChannel.class));
|
||||||
channelsBypassing.add(mock(NotificationChannel.class));
|
when(mBackend.getNotificationChannelsBypassingDnd(anyString(),
|
||||||
|
anyInt())).thenReturn(new ParceledListSlice<>(channelsBypassing));
|
||||||
|
|
||||||
when(mBackend.getNotificationChannelsBypassingDnd(entry.info.packageName,
|
// THEN there's are two preferences
|
||||||
entry.info.uid)).thenReturn(new ParceledListSlice<>(channelsBypassing));
|
mController.updateAppList(appEntries);
|
||||||
|
verify(mPreferenceCategory, times(2)).addPreference(any());
|
||||||
mController.updateNotificationChannelList(appEntries);
|
|
||||||
verify(mPreferenceScreen, times(3)).addPreference(any());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateNotificationChannelList_nullChannels() {
|
public void testUpdateAppList_nullApps() {
|
||||||
mController.updateNotificationChannelList(null);
|
mController.updateAppList(null);
|
||||||
verify(mPreferenceScreen, never()).addPreference(any());
|
verify(mPreferenceCategory, never()).addPreference(any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateNotificationChannelList_emptyChannelsList() {
|
public void testUpdateAppList_emptyAppList() {
|
||||||
mController.updateNotificationChannelList(new ArrayList<>());
|
// WHEN there are no apps
|
||||||
verify(mPreferenceScreen, never()).addPreference(any());
|
mController.updateAppList(new ArrayList<>());
|
||||||
|
|
||||||
|
// THEN only the appWithChannelsNoneBypassing makes it to the app list
|
||||||
|
ArgumentCaptor<Preference> prefCaptor = ArgumentCaptor.forClass(Preference.class);
|
||||||
|
verify(mPreferenceCategory).addPreference(prefCaptor.capture());
|
||||||
|
|
||||||
|
Preference pref = prefCaptor.getValue();
|
||||||
|
assertThat(pref.getKey()).isEqualTo(
|
||||||
|
ZenModeAllBypassingAppsPreferenceController.KEY_NO_APPS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,178 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2018 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.notification.zen;
|
|
||||||
|
|
||||||
import static android.provider.Settings.Global.ZEN_MODE;
|
|
||||||
import static android.provider.Settings.Global.ZEN_MODE_ALARMS;
|
|
||||||
import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
|
|
||||||
import static android.provider.Settings.Global.ZEN_MODE_NO_INTERRUPTIONS;
|
|
||||||
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
import android.app.NotificationManager;
|
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.provider.Settings;
|
|
||||||
|
|
||||||
import androidx.preference.ListPreference;
|
|
||||||
import androidx.preference.PreferenceScreen;
|
|
||||||
|
|
||||||
import com.android.settings.R;
|
|
||||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.MockitoAnnotations;
|
|
||||||
import org.robolectric.RobolectricTestRunner;
|
|
||||||
import org.robolectric.RuntimeEnvironment;
|
|
||||||
import org.robolectric.shadows.ShadowApplication;
|
|
||||||
import org.robolectric.util.ReflectionHelpers;
|
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
|
||||||
public class ZenModePriorityCallsPreferenceControllerTest {
|
|
||||||
|
|
||||||
private ZenModePriorityCallsPreferenceController mController;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private ZenModeBackend mBackend;
|
|
||||||
@Mock
|
|
||||||
private NotificationManager mNotificationManager;
|
|
||||||
@Mock
|
|
||||||
private ListPreference mockPref;
|
|
||||||
@Mock
|
|
||||||
private NotificationManager.Policy mPolicy;
|
|
||||||
@Mock
|
|
||||||
private PreferenceScreen mPreferenceScreen;
|
|
||||||
private ContentResolver mContentResolver;
|
|
||||||
private Context mContext;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Array Values Key
|
|
||||||
* 0: anyone
|
|
||||||
* 1: contacts
|
|
||||||
* 2: starred
|
|
||||||
* 3: none
|
|
||||||
*/
|
|
||||||
private String[] mValues;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setup() {
|
|
||||||
MockitoAnnotations.initMocks(this);
|
|
||||||
ShadowApplication shadowApplication = ShadowApplication.getInstance();
|
|
||||||
shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager);
|
|
||||||
|
|
||||||
mContext = RuntimeEnvironment.application;
|
|
||||||
mValues = mContext.getResources().getStringArray(R.array.zen_mode_contacts_values);
|
|
||||||
mContentResolver = RuntimeEnvironment.application.getContentResolver();
|
|
||||||
when(mNotificationManager.getNotificationPolicy()).thenReturn(mPolicy);
|
|
||||||
|
|
||||||
when(mBackend.getPriorityCallSenders())
|
|
||||||
.thenReturn(NotificationManager.Policy.PRIORITY_SENDERS_STARRED);
|
|
||||||
when(mBackend.getAlarmsTotalSilencePeopleSummary(
|
|
||||||
NotificationManager.Policy.PRIORITY_CATEGORY_CALLS)).thenCallRealMethod();
|
|
||||||
when(mBackend.getContactsSummary(NotificationManager.Policy.PRIORITY_CATEGORY_CALLS))
|
|
||||||
.thenCallRealMethod();
|
|
||||||
|
|
||||||
mController = new ZenModePriorityCallsPreferenceController(mContext, mock(Lifecycle.class));
|
|
||||||
ReflectionHelpers.setField(mController, "mBackend", mBackend);
|
|
||||||
|
|
||||||
when(mPreferenceScreen.findPreference(mController.getPreferenceKey())).thenReturn(mockPref);
|
|
||||||
mController.displayPreference(mPreferenceScreen);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void updateState_TotalSilence() {
|
|
||||||
Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_NO_INTERRUPTIONS);
|
|
||||||
|
|
||||||
when(mBackend.isPriorityCategoryEnabled(
|
|
||||||
NotificationManager.Policy.PRIORITY_CATEGORY_CALLS))
|
|
||||||
.thenReturn(false);
|
|
||||||
final ListPreference mockPref = mock(ListPreference.class);
|
|
||||||
mController.updateState(mockPref);
|
|
||||||
|
|
||||||
verify(mockPref).setEnabled(false);
|
|
||||||
verify(mockPref).setSummary(R.string.zen_mode_from_none_calls);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void updateState_AlarmsOnly() {
|
|
||||||
Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_ALARMS);
|
|
||||||
|
|
||||||
final ListPreference mockPref = mock(ListPreference.class);
|
|
||||||
mController.updateState(mockPref);
|
|
||||||
|
|
||||||
verify(mockPref).setEnabled(false);
|
|
||||||
verify(mockPref).setSummary(R.string.zen_mode_from_none_calls);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void updateState_Priority() {
|
|
||||||
Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS);
|
|
||||||
|
|
||||||
when(mBackend.isPriorityCategoryEnabled(
|
|
||||||
NotificationManager.Policy.PRIORITY_CATEGORY_CALLS))
|
|
||||||
.thenReturn(true);
|
|
||||||
|
|
||||||
mController.updateState(mockPref);
|
|
||||||
|
|
||||||
verify(mockPref).setEnabled(true);
|
|
||||||
verify(mockPref).setSummary(R.string.zen_mode_from_starred);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void onPreferenceChange_setSelectedContacts_any() {
|
|
||||||
Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS);
|
|
||||||
when(mBackend.getPriorityCallSenders()).thenReturn(
|
|
||||||
NotificationManager.Policy.PRIORITY_SENDERS_ANY);
|
|
||||||
mController.updateState(mockPref);
|
|
||||||
verify(mockPref).setValue(mValues[mController.getIndexOfSendersValue(
|
|
||||||
ZenModeBackend.ZEN_MODE_FROM_ANYONE)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void onPreferenceChange_setSelectedContacts_none() {
|
|
||||||
Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS);
|
|
||||||
when(mBackend.getPriorityCallSenders()).thenReturn(ZenModeBackend.SOURCE_NONE);
|
|
||||||
mController.updateState(mockPref);
|
|
||||||
verify(mockPref).setValue(mValues[mController.getIndexOfSendersValue(
|
|
||||||
ZenModeBackend.ZEN_MODE_FROM_NONE)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void onPreferenceChange_setSelectedContacts_starred() {
|
|
||||||
Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS);
|
|
||||||
when(mBackend.getPriorityCallSenders()).thenReturn(
|
|
||||||
NotificationManager.Policy.PRIORITY_SENDERS_STARRED);
|
|
||||||
mController.updateState(mockPref);
|
|
||||||
verify(mockPref).setValue(mValues[mController.getIndexOfSendersValue(
|
|
||||||
ZenModeBackend.ZEN_MODE_FROM_STARRED)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void onPreferenceChange_setSelectedContacts_contacts() {
|
|
||||||
Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS);
|
|
||||||
when(mBackend.getPriorityCallSenders()).thenReturn(
|
|
||||||
NotificationManager.Policy.PRIORITY_SENDERS_CONTACTS);
|
|
||||||
mController.updateState(mockPref);
|
|
||||||
verify(mockPref).setValue(mValues[mController.getIndexOfSendersValue(
|
|
||||||
ZenModeBackend.ZEN_MODE_FROM_CONTACTS)]);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -79,13 +79,13 @@ public class ZenModeSettingsTest {
|
|||||||
public void testGetCallsSettingSummary_contacts() {
|
public void testGetCallsSettingSummary_contacts() {
|
||||||
Policy policy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS | Policy.PRIORITY_CATEGORY_CALLS,
|
Policy policy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS | Policy.PRIORITY_CATEGORY_CALLS,
|
||||||
Policy.PRIORITY_SENDERS_CONTACTS, 0, 0);
|
Policy.PRIORITY_SENDERS_CONTACTS, 0, 0);
|
||||||
assertThat(mBuilder.getCallsSettingSummary(policy)).isEqualTo("Allow from contacts");
|
assertThat(mBuilder.getCallsSettingSummary(policy)).isEqualTo("Contacts");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetCallsSettingSummary_repeatCallers() {
|
public void testGetCallsSettingSummary_repeatCallers() {
|
||||||
Policy policy = new Policy(Policy.PRIORITY_CATEGORY_REPEAT_CALLERS, 0, 0, 0);
|
Policy policy = new Policy(Policy.PRIORITY_CATEGORY_REPEAT_CALLERS, 0, 0, 0);
|
||||||
assertThat(mBuilder.getCallsSettingSummary(policy)).isEqualTo("Allow from repeat callers");
|
assertThat(mBuilder.getCallsSettingSummary(policy)).isEqualTo("Repeat callers");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -94,7 +94,7 @@ public class ZenModeSettingsTest {
|
|||||||
Policy.PRIORITY_CATEGORY_REPEAT_CALLERS | Policy.PRIORITY_CATEGORY_CALLS,
|
Policy.PRIORITY_CATEGORY_REPEAT_CALLERS | Policy.PRIORITY_CATEGORY_CALLS,
|
||||||
Policy.PRIORITY_SENDERS_STARRED, 0, 0);
|
Policy.PRIORITY_SENDERS_STARRED, 0, 0);
|
||||||
assertThat(mBuilder.getCallsSettingSummary(policy))
|
assertThat(mBuilder.getCallsSettingSummary(policy))
|
||||||
.isEqualTo("Allow from starred contacts and repeat callers");
|
.isEqualTo("Starred contacts and repeat callers");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Reference in New Issue
Block a user